aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin
diff options
context:
space:
mode:
Diffstat (limited to 'java/src/com/android/inputmethod/latin')
-rw-r--r--java/src/com/android/inputmethod/latin/BinaryDictionary.java4
-rwxr-xr-xjava/src/com/android/inputmethod/latin/CandidateView.java6
-rw-r--r--java/src/com/android/inputmethod/latin/KeyboardSwitcher.java64
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java118
-rw-r--r--java/src/com/android/inputmethod/latin/LatinImeLogger.java393
-rw-r--r--java/src/com/android/inputmethod/latin/TextEntryState.java2
6 files changed, 531 insertions, 56 deletions
diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
index 6473f4558..5d3df4e6c 100644
--- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java
+++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java
@@ -51,9 +51,9 @@ public class BinaryDictionary extends Dictionary {
static {
try {
- System.loadLibrary("jni_latinime");
+ System.loadLibrary("jni_latinime2");
} catch (UnsatisfiedLinkError ule) {
- Log.e("BinaryDictionary", "Could not load native library jni_latinime");
+ Log.e("BinaryDictionary", "Could not load native library jni_latinime2");
}
}
diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java
index ae45001b8..3234e2484 100755
--- a/java/src/com/android/inputmethod/latin/CandidateView.java
+++ b/java/src/com/android/inputmethod/latin/CandidateView.java
@@ -167,7 +167,7 @@ public class CandidateView extends View {
if (scrollX < 0) {
scrollX = 0;
}
- if (distanceX > 0 && scrollX + width > mTotalWidth) {
+ if (distanceX > 0 && scrollX + width > mTotalWidth) {
scrollX -= (int) distanceX;
}
mTargetScrollX = scrollX;
@@ -412,7 +412,11 @@ public class CandidateView extends View {
if (y <= 0) {
// Fling up!?
if (mSelectedString != null) {
+ // If there are completions from the application, we don't change the state to
+ // STATE_PICKED_SUGGESTION
if (!mShowingCompletions) {
+ // This "acceptedSuggestion" will not be counted as a word because
+ // it will be counted in pickSuggestion instead.
TextEntryState.acceptedSuggestion(mSuggestions.get(0),
mSelectedString);
}
diff --git a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
index 1a196448f..5a271f264 100644
--- a/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/latin/KeyboardSwitcher.java
@@ -21,11 +21,12 @@ import java.util.Locale;
import java.util.Map;
import android.content.Context;
+import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.inputmethodservice.InputMethodService;
+import android.preference.PreferenceManager;
-public class KeyboardSwitcher {
+public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final int MODE_TEXT = 1;
public static final int MODE_SYMBOLS = 2;
@@ -45,6 +46,13 @@ public class KeyboardSwitcher {
public static final int KEYBOARDMODE_IM = R.id.mode_im;
public static final int KEYBOARDMODE_WEB = R.id.mode_webentry;
+ public static final String DEFAULT_LAYOUT_ID = "3";
+ public static final String PREF_KEYBOARD_LAYOUT = "keyboard_layout";
+ private static final int[] LAYOUTS = new int [] {
+ R.layout.input, R.layout.input2, R.layout.input3, R.layout.input4, R.layout.input5,
+ R.layout.input6
+ };
+
private static final int SYMBOLS_MODE_STATE_NONE = 0;
private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
@@ -57,9 +65,8 @@ public class KeyboardSwitcher {
KEYBOARDMODE_IM,
KEYBOARDMODE_WEB};
- //LatinIME mContext;
Context mContext;
- InputMethodService mInputMethodService;
+ LatinIME mInputMethodService;
private KeyboardId mSymbolsId;
private KeyboardId mSymbolsShiftedId;
@@ -79,14 +86,20 @@ public class KeyboardSwitcher {
private int mLastDisplayWidth;
private LanguageSwitcher mLanguageSwitcher;
private Locale mInputLocale;
- private boolean mEnableMultipleLanguages;
- KeyboardSwitcher(Context context, InputMethodService ims) {
+ private int mLayoutId;
+
+ KeyboardSwitcher(Context context, LatinIME ims) {
mContext = context;
mKeyboards = new HashMap<KeyboardId, LatinKeyboard>();
mSymbolsId = new KeyboardId(R.xml.kbd_symbols, false);
mSymbolsShiftedId = new KeyboardId(R.xml.kbd_symbols_shift, false);
mInputMethodService = ims;
+
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims);
+ int mLayoutId = Integer.valueOf(prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
+ prefs.registerOnSharedPreferenceChangeListener(this);
+ changeLatinKeyboardView(mLayoutId, false);
}
/**
@@ -98,13 +111,12 @@ public class KeyboardSwitcher {
void setLanguageSwitcher(LanguageSwitcher languageSwitcher) {
mLanguageSwitcher = languageSwitcher;
mInputLocale = mLanguageSwitcher.getInputLocale();
- mEnableMultipleLanguages = mLanguageSwitcher.getLocaleCount() > 1;
}
void setInputView(LatinKeyboardView inputView) {
mInputView = inputView;
}
-
+
void makeKeyboards(boolean forceCreate) {
if (forceCreate) mKeyboards.clear();
// Configuration change is coming after the keyboard gets recreated. So don't rely on that.
@@ -140,6 +152,7 @@ public class KeyboardSwitcher {
this(xml, 0, false, hasVoice);
}
+ @Override
public boolean equals(Object other) {
return other instanceof KeyboardId && equals((KeyboardId) other);
}
@@ -150,6 +163,7 @@ public class KeyboardSwitcher {
&& other.mEnableShiftLock == this.mEnableShiftLock;
}
+ @Override
public int hashCode() {
return (mXml + 1) * (mKeyboardMode + 1) * (mEnableShiftLock ? 2 : 1)
* (mHasVoice ? 4 : 8);
@@ -348,4 +362,38 @@ public class KeyboardSwitcher {
}
return false;
}
+
+ public LatinKeyboardView getInputView() {
+ return mInputView;
+ }
+
+ public void recreateInputView() {
+ changeLatinKeyboardView(mLayoutId, true);
+ }
+
+ private void changeLatinKeyboardView(int newLayout, boolean forceReset) {
+ if (mLayoutId != newLayout || mInputView == null || forceReset) {
+ if (LAYOUTS.length <= newLayout) {
+ newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID);
+ }
+ mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater().inflate(
+ LAYOUTS[newLayout], null);
+ mInputView.setOnKeyboardActionListener(mInputMethodService);
+ mLayoutId = newLayout;
+ }
+ mInputMethodService.mHandler.post(new Runnable() {
+ public void run() {
+ if (mInputView != null) {
+ mInputMethodService.setInputView(mInputView);
+ }
+ mInputMethodService.updateInputViewShown();
+ }});
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (PREF_KEYBOARD_LAYOUT.equals(key)) {
+ changeLatinKeyboardView(
+ Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false);
+ }
+ }
}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index db0a822ed..a02a59e8c 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -146,7 +146,7 @@ public class LatinIME extends InputMethodService
private static final int POS_SETTINGS = 0;
private static final int POS_METHOD = 1;
- private LatinKeyboardView mInputView;
+ //private LatinKeyboardView mInputView;
private CandidateViewContainer mCandidateViewContainer;
private CandidateView mCandidateView;
private Suggest mSuggest;
@@ -249,8 +249,9 @@ public class LatinIME extends InputMethodService
break;
case MSG_START_TUTORIAL:
if (mTutorial == null) {
- if (mInputView.isShown()) {
- mTutorial = new Tutorial(LatinIME.this, mInputView);
+ if (mKeyboardSwitcher.getInputView().isShown()) {
+ mTutorial = new Tutorial(
+ LatinIME.this, mKeyboardSwitcher.getInputView());
mTutorial.start();
} else {
// Try again soon if the view is not yet showing
@@ -309,6 +310,7 @@ public class LatinIME extends InputMethodService
});
}
prefs.registerOnSharedPreferenceChangeListener(this);
+ LatinImeLogger.init(this);
}
private void initSuggest(String locale) {
@@ -354,6 +356,7 @@ public class LatinIME extends InputMethodService
if (VOICE_INSTALLED) {
mVoiceInput.destroy();
}
+ LatinImeLogger.commit();
super.onDestroy();
}
@@ -393,15 +396,12 @@ public class LatinIME extends InputMethodService
@Override
public View onCreateInputView() {
- mInputView = (LatinKeyboardView) getLayoutInflater().inflate(
- R.layout.input, null);
- mKeyboardSwitcher.setInputView(mInputView);
+ mKeyboardSwitcher.recreateInputView();
mKeyboardSwitcher.makeKeyboards(true);
- mInputView.setOnKeyboardActionListener(this);
mKeyboardSwitcher.setKeyboardMode(
KeyboardSwitcher.MODE_TEXT, 0,
shouldShowVoiceButton(makeFieldContext(), getCurrentInputEditorInfo()));
- return mInputView;
+ return mKeyboardSwitcher.getInputView();
}
@Override
@@ -418,8 +418,9 @@ public class LatinIME extends InputMethodService
@Override
public void onStartInputView(EditorInfo attribute, boolean restarting) {
+ LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
// In landscape mode, this method gets called without the input view being created.
- if (mInputView == null) {
+ if (inputView == null) {
return;
}
@@ -528,7 +529,7 @@ public class LatinIME extends InputMethodService
attribute.imeOptions, enableVoiceButton);
updateShiftKeyState(attribute);
}
- mInputView.closing();
+ inputView.closing();
mComposing.setLength(0);
mPredicting = false;
mDeleteCount = 0;
@@ -544,7 +545,7 @@ public class LatinIME extends InputMethodService
updateCorrectionMode();
- mInputView.setProximityCorrectionEnabled(true);
+ inputView.setProximityCorrectionEnabled(true);
mPredictionOn = mPredictionOn && (mCorrectionMode > 0 || mShowSuggestions);
checkTutorial(attribute.privateImeOptions);
if (TRACE) Debug.startMethodTracing("/data/trace/latinime");
@@ -554,6 +555,8 @@ public class LatinIME extends InputMethodService
public void onFinishInput() {
super.onFinishInput();
+ LatinImeLogger.commit();
+
if (VOICE_INSTALLED && !mConfigurationChanging) {
if (mAfterVoiceInput) {
mVoiceInput.flushAllTextModificationCounters();
@@ -562,8 +565,8 @@ public class LatinIME extends InputMethodService
mVoiceInput.flushLogs();
mVoiceInput.cancel();
}
- if (mInputView != null) {
- mInputView.closing();
+ if (mKeyboardSwitcher.getInputView() != null) {
+ mKeyboardSwitcher.getInputView().closing();
}
if (mAutoDictionary != null) mAutoDictionary.flushPendingWrites();
}
@@ -655,6 +658,8 @@ public class LatinIME extends InputMethodService
@Override
public void hideWindow() {
+ LatinImeLogger.commit();
+
if (TRACE) Debug.stopMethodTracing();
if (mOptionsDialog != null && mOptionsDialog.isShowing()) {
mOptionsDialog.dismiss();
@@ -695,7 +700,7 @@ public class LatinIME extends InputMethodService
CompletionInfo ci = completions[i];
if (ci != null) stringList.add(ci.getText());
}
- //CharSequence typedWord = mWord.getTypedWord();
+ // When in fullscreen mode, show completions generated by the application
setSuggestions(stringList, true, true, true);
mBestWord = null;
setCandidatesViewShown(isCandidateStripVisible() || mCompletionOn);
@@ -707,7 +712,8 @@ public class LatinIME extends InputMethodService
// TODO: Remove this if we support candidates with hard keyboard
if (onEvaluateInputViewShown()) {
// Show the candidates view only if input view is showing
- super.setCandidatesViewShown(shown && mInputView != null && mInputView.isShown());
+ super.setCandidatesViewShown(shown && mKeyboardSwitcher.getInputView() != null
+ && mKeyboardSwitcher.getInputView().isShown());
}
}
@@ -736,8 +742,8 @@ public class LatinIME extends InputMethodService
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
- if (event.getRepeatCount() == 0 && mInputView != null) {
- if (mInputView.handleBack()) {
+ if (event.getRepeatCount() == 0 && mKeyboardSwitcher.getInputView() != null) {
+ if (mKeyboardSwitcher.getInputView().handleBack()) {
return true;
} else if (mTutorial != null) {
mTutorial.close();
@@ -769,8 +775,10 @@ public class LatinIME extends InputMethodService
if (mTutorial != null) {
return true;
}
+ LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
// Enable shift key and DPAD to do selections
- if (mInputView != null && mInputView.isShown() && mInputView.isShifted()) {
+ if (inputView != null && inputView.isShown()
+ && inputView.isShifted()) {
event = new KeyEvent(event.getDownTime(), event.getEventTime(),
event.getAction(), event.getKeyCode(), event.getRepeatCount(),
event.getDeviceId(), event.getScanCode(),
@@ -803,7 +811,7 @@ public class LatinIME extends InputMethodService
mKeyboardSwitcher = new KeyboardSwitcher(this, this);
}
mKeyboardSwitcher.setLanguageSwitcher(mLanguageSwitcher);
- if (mInputView != null) {
+ if (mKeyboardSwitcher.getInputView() != null) {
mKeyboardSwitcher.setVoiceMode(mEnableVoice && mEnableVoiceButton, mVoiceOnPrimary);
}
mKeyboardSwitcher.makeKeyboards(true);
@@ -831,9 +839,10 @@ public class LatinIME extends InputMethodService
public void updateShiftKeyState(EditorInfo attr) {
InputConnection ic = getCurrentInputConnection();
- if (attr != null && mInputView != null && mKeyboardSwitcher.isAlphabetMode()
- && ic != null) {
- mInputView.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0);
+ if (attr != null && mKeyboardSwitcher.getInputView() != null
+ && mKeyboardSwitcher.isAlphabetMode() && ic != null) {
+ mKeyboardSwitcher.getInputView().setShifted(
+ mCapsLock || getCursorCapsMode(ic, attr) != 0);
}
}
@@ -946,6 +955,7 @@ public class LatinIME extends InputMethodService
case Keyboard.KEYCODE_DELETE:
handleBackspace();
mDeleteCount++;
+ LatinImeLogger.logOnDelete(1);
break;
case Keyboard.KEYCODE_SHIFT:
handleShift();
@@ -991,6 +1001,7 @@ public class LatinIME extends InputMethodService
} else {
handleCharacter(primaryCode, keyCodes);
}
+ LatinImeLogger.logOnInputChar(1);
// Cancel the just reverted state
mJustRevertedSeparator = null;
}
@@ -1080,7 +1091,8 @@ public class LatinIME extends InputMethodService
if (mKeyboardSwitcher.isAlphabetMode()) {
// Alphabet keyboard
checkToggleCapsLock();
- mInputView.setShifted(mCapsLock || !mInputView.isShifted());
+ mKeyboardSwitcher.getInputView().setShifted(mCapsLock
+ || !mKeyboardSwitcher.getInputView().isShifted());
} else {
mKeyboardSwitcher.toggleShift();
}
@@ -1103,7 +1115,7 @@ public class LatinIME extends InputMethodService
mWord.reset();
}
}
- if (mInputView.isShifted()) {
+ if (mKeyboardSwitcher.getInputView().isShifted()) {
// TODO: This doesn't work with ß, need to fix it in the next release.
if (keyCodes == null || keyCodes[0] < Character.MIN_CODE_POINT
|| keyCodes[0] > Character.MAX_CODE_POINT) {
@@ -1112,7 +1124,7 @@ public class LatinIME extends InputMethodService
primaryCode = new String(keyCodes, 0, 1).toUpperCase().charAt(0);
}
if (mPredicting) {
- if (mInputView.isShifted() && mComposing.length() == 0) {
+ if (mKeyboardSwitcher.getInputView().isShifted() && mComposing.length() == 0) {
mWord.setCapitalized(true);
}
mComposing.append((char) primaryCode);
@@ -1207,12 +1219,12 @@ public class LatinIME extends InputMethodService
mVoiceInput.cancel();
}
requestHideSelf(0);
- mInputView.closing();
+ mKeyboardSwitcher.getInputView().closing();
TextEntryState.endSession();
}
private void checkToggleCapsLock() {
- if (mInputView.getKeyboard().isShifted()) {
+ if (mKeyboardSwitcher.getInputView().getKeyboard().isShifted()) {
toggleCapsLock();
}
}
@@ -1220,7 +1232,8 @@ public class LatinIME extends InputMethodService
private void toggleCapsLock() {
mCapsLock = !mCapsLock;
if (mKeyboardSwitcher.isAlphabetMode()) {
- ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
+ ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setShiftLocked(
+ mCapsLock);
}
}
@@ -1248,8 +1261,8 @@ public class LatinIME extends InputMethodService
mHandler.post(new Runnable() {
public void run() {
mRecognizing = false;
- if (mInputView != null) {
- setInputView(mInputView);
+ if (mKeyboardSwitcher.getInputView() != null) {
+ setInputView(mKeyboardSwitcher.getInputView());
}
updateInputViewShown();
}});
@@ -1348,7 +1361,7 @@ public class LatinIME extends InputMethodService
Window window = mVoiceWarningDialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
- lp.token = mInputView.getWindowToken();
+ lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(lp);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
@@ -1384,7 +1397,8 @@ public class LatinIME extends InputMethodService
final List<CharSequence> nBest = new ArrayList<CharSequence>();
boolean capitalizeFirstWord = preferCapitalization()
- || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted());
+ || (mKeyboardSwitcher.isAlphabetMode()
+ && mKeyboardSwitcher.getInputView().isShifted());
for (String c : mVoiceResults.candidates) {
if (capitalizeFirstWord) {
c = Character.toUpperCase(c.charAt(0)) + c.substring(1, c.length());
@@ -1442,7 +1456,8 @@ public class LatinIME extends InputMethodService
private void updateSuggestions() {
mSuggestionShouldReplaceCurrentWord = false;
- ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null);
+ LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
+ ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null);
// Check if we have a suggestion engine attached.
if ((mSuggest == null || !isPredictionOn()) && !mVoiceInputHighlighted) {
@@ -1454,17 +1469,20 @@ public class LatinIME extends InputMethodService
return;
}
- List<CharSequence> stringList = mSuggest.getSuggestions(mInputView, mWord, false);
+ List<CharSequence> stringList = mSuggest.getSuggestions(inputView,
+ mWord, false);
int[] nextLettersFrequencies = mSuggest.getNextLettersFrequencies();
- ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(nextLettersFrequencies);
+ ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(
+ nextLettersFrequencies);
boolean correctionAvailable = !mInputTypeNoAutoCorrect && mSuggest.hasMinimalCorrection();
//|| mCorrectionMode == mSuggest.CORRECTION_FULL;
CharSequence typedWord = mWord.getTypedWord();
// If we're in basic correct
boolean typedWordValid = mSuggest.isValidWord(typedWord) ||
- (preferCapitalization() && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
+ (preferCapitalization()
+ && mSuggest.isValidWord(typedWord.toString().toLowerCase()));
if (mCorrectionMode == Suggest.CORRECTION_FULL) {
correctionAvailable |= typedWordValid;
}
@@ -1531,6 +1549,10 @@ public class LatinIME extends InputMethodService
// If this is a punctuation, apply it through the normal key press
if (suggestion.length() == 1 && isWordSeparator(suggestion.charAt(0))) {
+ // Word separators are suggested before the user inputs something.
+ // So, LatinImeLogger logs suggestion.charAt(0) as a user's input.
+ LatinImeLogger.logOnClickSuggestion(
+ suggestion.toString(), suggestion.toString(), index);
onKey(suggestion.charAt(0), null);
if (ic != null) {
ic.endBatchEdit();
@@ -1543,6 +1565,8 @@ public class LatinIME extends InputMethodService
if (index == 0) {
checkAddToDictionary(suggestion, AutoDictionary.FREQUENCY_FOR_PICKED);
}
+ LatinImeLogger.logOnClickSuggestion(
+ mComposing.toString(), suggestion.toString(), index);
TextEntryState.acceptedSuggestion(mComposing.toString(), suggestion);
// Follow it with a space
if (mAutoSpace) {
@@ -1560,10 +1584,12 @@ public class LatinIME extends InputMethodService
}
private void pickSuggestion(CharSequence suggestion) {
+ LatinKeyboardView inputView = mKeyboardSwitcher.getInputView();
if (mCapsLock) {
suggestion = suggestion.toString().toUpperCase();
} else if (preferCapitalization()
- || (mKeyboardSwitcher.isAlphabetMode() && mInputView.isShifted())) {
+ || (mKeyboardSwitcher.isAlphabetMode()
+ && inputView.isShifted())) {
suggestion = suggestion.toString().toUpperCase().charAt(0)
+ suggestion.subSequence(1, suggestion.length()).toString();
}
@@ -1578,7 +1604,7 @@ public class LatinIME extends InputMethodService
}
mPredicting = false;
mCommittedLength = suggestion.length();
- ((LatinKeyboard) mInputView.getKeyboard()).setPreferredLetters(null);
+ ((LatinKeyboard) inputView.getKeyboard()).setPreferredLetters(null);
setNextSuggestions();
updateShiftKeyState(getCurrentInputEditorInfo());
}
@@ -1678,7 +1704,7 @@ public class LatinIME extends InputMethodService
ClipboardManager cm = ((ClipboardManager)getSystemService(CLIPBOARD_SERVICE));
CharSequence text = cm.getText();
if (!TextUtils.isEmpty(text)) {
- mInputView.startPlaying(text.toString());
+ mKeyboardSwitcher.getInputView().startPlaying(text.toString());
}
}
}
@@ -1729,7 +1755,7 @@ public class LatinIME extends InputMethodService
public void onRelease(int primaryCode) {
// Reset any drag flags in the keyboard
- ((LatinKeyboard) mInputView.getKeyboard()).keyReleased();
+ ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased();
//vibrate();
}
@@ -1781,7 +1807,7 @@ public class LatinIME extends InputMethodService
// if mAudioManager is null, we don't have the ringer state yet
// mAudioManager will be set by updateRingerMode
if (mAudioManager == null) {
- if (mInputView != null) {
+ if (mKeyboardSwitcher.getInputView() != null) {
updateRingerMode();
}
}
@@ -1808,8 +1834,9 @@ public class LatinIME extends InputMethodService
if (!mVibrateOn) {
return;
}
- if (mInputView != null) {
- mInputView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
+ if (mKeyboardSwitcher.getInputView() != null) {
+ mKeyboardSwitcher.getInputView().performHapticFeedback(
+ HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
}
}
@@ -1960,7 +1987,7 @@ public class LatinIME extends InputMethodService
mOptionsDialog = builder.create();
Window window = mOptionsDialog.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
- lp.token = mInputView.getWindowToken();
+ lp.token = mKeyboardSwitcher.getInputView().getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
window.setAttributes(lp);
window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
@@ -1970,7 +1997,8 @@ public class LatinIME extends InputMethodService
private void changeKeyboardMode() {
mKeyboardSwitcher.toggleSymbols();
if (mCapsLock && mKeyboardSwitcher.isAlphabetMode()) {
- ((LatinKeyboard) mInputView.getKeyboard()).setShiftLocked(mCapsLock);
+ ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).setShiftLocked(
+ mCapsLock);
}
updateShiftKeyState(getCurrentInputEditorInfo());
diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
new file mode 100644
index 000000000..dcd1962c0
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java
@@ -0,0 +1,393 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.latin;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.DropBoxManager;
+import android.preference.PreferenceManager;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChangeListener {
+ private static final String TAG = "LatinIMELogs";
+ private static boolean sDBG = false;
+ // DEFAULT_LOG_ENABLED should be false when released to public.
+ private static final boolean DEFAULT_LOG_ENABLED = true;
+
+ private static final long MINIMUMSENDINTERVAL = 300 * DateUtils.SECOND_IN_MILLIS; // 300 sec
+ private static final long MINIMUMCOUNTINTERVAL = 20 * DateUtils.SECOND_IN_MILLIS; // 20 sec
+ private static final char SEPARATER = ';';
+ private static final int ID_CLICKSUGGESTION = 0;
+ private static final int ID_AUTOSUGGESTION = 1;
+ private static final int ID_AUTOSUGGESTIONCANCELED = 2;
+ private static final int ID_INPUT_COUNT = 3;
+ private static final int ID_DELETE_COUNT = 4;
+ private static final int ID_WORD_COUNT = 5;
+ private static final int ID_ACTUAL_CHAR_COUNT = 6;
+ private static final int ID_THEME_ID = 7;
+
+ private static final String PREF_ENABLE_LOG = "enable_logging";
+ private static final String PREF_DEBUG_MODE = "debug_mode";
+
+ public static boolean sLogEnabled = true;
+ private static LatinImeLogger sLatinImeLogger = new LatinImeLogger();
+ // Store the last auto suggested word.
+ // This is required for a cancellation log of auto suggestion of that word.
+ private static String sLastAutoSuggestBefore;
+ private static String sLastAutoSuggestAfter;
+
+ private ArrayList<LogEntry> mLogBuffer = null;
+ private ArrayList<LogEntry> mPrivacyLogBuffer = null;
+ private Context mContext = null;
+ private DropBoxManager mDropBox = null;
+ private long mLastTimeActive;
+ private long mLastTimeSend;
+ private long mLastTimeCountEntry;
+
+ private String mThemeId;
+ private int mDeleteCount;
+ private int mInputCount;
+ private int mWordCount;
+ // ActualCharCount includes all characters that were completed.
+ private int mActualCharCount;
+
+ private static class LogEntry implements Comparable<LogEntry> {
+ public final int mTag;
+ public final String[] mData;
+ public long mTime;
+
+ public LogEntry (long time, int tag, String[] data) {
+ mTag = tag;
+ mTime = time;
+ mData = data;
+ }
+
+ public int compareTo(LogEntry log2) {
+ if (mData.length == 0 && log2.mData.length == 0) {
+ return 0;
+ } else if (mData.length == 0) {
+ return 1;
+ } else if (log2.mData.length == 0) {
+ return -1;
+ }
+ return log2.mData[0].compareTo(mData[0]);
+ }
+ }
+
+ private void initInternal(Context context) {
+ mContext = context;
+ mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
+ mLastTimeSend = System.currentTimeMillis();
+ mLastTimeActive = mLastTimeSend;
+ mLastTimeCountEntry = mLastTimeSend;
+ mDeleteCount = 0;
+ mInputCount = 0;
+ mWordCount = 0;
+ mActualCharCount = 0;
+ mLogBuffer = new ArrayList<LogEntry>();
+ mPrivacyLogBuffer = new ArrayList<LogEntry>();
+ final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ sLogEnabled = prefs.getBoolean(PREF_ENABLE_LOG, DEFAULT_LOG_ENABLED);
+ mThemeId = prefs.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT,
+ KeyboardSwitcher.DEFAULT_LAYOUT_ID);
+ sDBG = prefs.getBoolean(PREF_DEBUG_MODE, sDBG);
+ prefs.registerOnSharedPreferenceChangeListener(this);
+ }
+
+ /**
+ * Clear all logged data
+ */
+ private void reset() {
+ mDeleteCount = 0;
+ mInputCount = 0;
+ mWordCount = 0;
+ mActualCharCount = 0;
+ mLogBuffer.clear();
+ mPrivacyLogBuffer.clear();
+ }
+
+ /**
+ * Check if the input string is safe as an entry or not.
+ */
+ private static boolean checkStringDataSafe(String s) {
+ if (sDBG) {
+ Log.d(TAG, "Check String safety: " + s);
+ }
+ for (int i = 0; i < s.length(); ++i) {
+ if (!Character.isDigit(s.charAt(i))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void addCountEntry(long time) {
+ if (sDBG) {
+ Log.d(TAG, "Log counts. (4)");
+ }
+ mLogBuffer.add(new LogEntry (time, ID_DELETE_COUNT,
+ new String[] {String.valueOf(mDeleteCount)}));
+ mLogBuffer.add(new LogEntry (time, ID_INPUT_COUNT,
+ new String[] {String.valueOf(mInputCount)}));
+ mLogBuffer.add(new LogEntry (time, ID_WORD_COUNT,
+ new String[] {String.valueOf(mWordCount)}));
+ mLogBuffer.add(new LogEntry (time, ID_ACTUAL_CHAR_COUNT,
+ new String[] {String.valueOf(mActualCharCount)}));
+ mDeleteCount = 0;
+ mInputCount = 0;
+ mWordCount = 0;
+ mActualCharCount = 0;
+ mLastTimeCountEntry = time;
+ }
+
+ private void addThemeIdEntry(long time) {
+ if (sDBG) {
+ Log.d(TAG, "Log theme Id. (1)");
+ }
+ mLogBuffer.add(new LogEntry (time, ID_THEME_ID,
+ new String[] {mThemeId}));
+ }
+
+ private void flushPrivacyLogSafely() {
+ if (sDBG) {
+ Log.d(TAG, "Log theme Id. (" + mPrivacyLogBuffer.size() + ")");
+ }
+ long now = System.currentTimeMillis();
+ Collections.sort(mPrivacyLogBuffer);
+ for (LogEntry l: mPrivacyLogBuffer) {
+ l.mTime = now;
+ mLogBuffer.add(l);
+ }
+ mPrivacyLogBuffer.clear();
+ }
+
+ /**
+ * Add an entry
+ * @param tag
+ * @param data
+ */
+ private void addData(int tag, Object data) {
+ switch (tag) {
+ case ID_DELETE_COUNT:
+ if (((mLastTimeActive - mLastTimeCountEntry) > MINIMUMCOUNTINTERVAL)
+ || (mDeleteCount == 0 && mInputCount == 0)) {
+ addCountEntry(mLastTimeActive);
+ addThemeIdEntry(mLastTimeActive);
+ }
+ mDeleteCount += (Integer)data;
+ break;
+ case ID_INPUT_COUNT:
+ if (((mLastTimeActive - mLastTimeCountEntry) > MINIMUMCOUNTINTERVAL)
+ || (mDeleteCount == 0 && mInputCount == 0)) {
+ addCountEntry(mLastTimeActive);
+ addThemeIdEntry(mLastTimeActive);
+ }
+ mInputCount += (Integer)data;
+ break;
+ case ID_CLICKSUGGESTION:
+ case ID_AUTOSUGGESTION:
+ ++mWordCount;
+ String[] dataStrings = (String[]) data;
+ if (dataStrings.length < 2) {
+ if (sDBG) {
+ Log.e(TAG, "The length of logged string array is invalid.");
+ }
+ break;
+ }
+ mActualCharCount += dataStrings[1].length();
+ if (checkStringDataSafe(dataStrings[0]) && checkStringDataSafe(dataStrings[1])) {
+ mPrivacyLogBuffer.add(
+ new LogEntry (System.currentTimeMillis(), tag, dataStrings));
+ } else {
+ if (sDBG) {
+ Log.d(TAG, "Skipped to add an entry because data is unsafe.");
+ }
+ }
+ break;
+ case ID_AUTOSUGGESTIONCANCELED:
+ --mWordCount;
+ dataStrings = (String[]) data;
+ if (dataStrings.length < 2) {
+ if (sDBG) {
+ Log.e(TAG, "The length of logged string array is invalid.");
+ }
+ break;
+ }
+ mActualCharCount -= dataStrings[1].length();
+ if (checkStringDataSafe(dataStrings[0]) && checkStringDataSafe(dataStrings[1])) {
+ mPrivacyLogBuffer.add(
+ new LogEntry (System.currentTimeMillis(), tag, dataStrings));
+ } else {
+ if (sDBG) {
+ Log.d(TAG, "Skipped to add an entry because data is unsafe.");
+ }
+ }
+ break;
+ default:
+ if (sDBG) {
+ Log.e(TAG, "Log Tag is not entried.");
+ }
+ break;
+ }
+ }
+
+ private void commitInternal() {
+ if (sDBG) {
+ Log.d(TAG, "Commit (" + mLogBuffer.size() + ")");
+ }
+ flushPrivacyLogSafely();
+ long now = System.currentTimeMillis();
+ addCountEntry(now);
+ addThemeIdEntry(now);
+ String s = LogSerializer.createStringFromEntries(mLogBuffer);
+ if (!TextUtils.isEmpty(s)) {
+ if (sDBG) {
+ Log.d(TAG, "Commit log: " + s);
+ }
+ mDropBox.addText(TAG, s);
+ }
+ reset();
+ mLastTimeSend = now;
+ }
+
+ private synchronized void sendLogToDropBox(int tag, Object s) {
+ long now = System.currentTimeMillis();
+ if (sDBG) {
+ String out = "";
+ if (s instanceof String[]) {
+ for (String str: ((String[]) s)) {
+ out += str + ",";
+ }
+ } else if (s instanceof Integer) {
+ out += (Integer) s;
+ }
+ Log.d(TAG, "SendLog: " + tag + ";" + out + ", will be sent after "
+ + (- (now - mLastTimeSend - MINIMUMSENDINTERVAL) / 1000) + " sec.");
+ }
+ if (now - mLastTimeActive > MINIMUMSENDINTERVAL) {
+ // Send a log before adding an log entry if the last data is too old.
+ commitInternal();
+ addData(tag, s);
+ } else if (now - mLastTimeSend > MINIMUMSENDINTERVAL) {
+ // Send a log after adding an log entry.
+ addData(tag, s);
+ commitInternal();
+ } else {
+ addData(tag, s);
+ }
+ mLastTimeActive = now;
+ }
+
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
+ if (PREF_ENABLE_LOG.equals(key)) {
+ if (sharedPreferences.getBoolean(key, DEFAULT_LOG_ENABLED)) {
+ sLogEnabled = (mContext != null);
+ } else {
+ sLogEnabled = false;
+ }
+ } else if (KeyboardSwitcher.PREF_KEYBOARD_LAYOUT.equals(key)) {
+ mThemeId = sharedPreferences.getString(KeyboardSwitcher.PREF_KEYBOARD_LAYOUT,
+ KeyboardSwitcher.DEFAULT_LAYOUT_ID);
+ } else if (PREF_DEBUG_MODE.equals(key)) {
+ sDBG = sharedPreferences.getBoolean(PREF_DEBUG_MODE, sDBG);
+ }
+ }
+
+ public static void init(Context context) {
+ sLatinImeLogger.initInternal(context);
+ }
+
+ public static void commit() {
+ if (sLogEnabled) {
+ sLatinImeLogger.commitInternal();
+ }
+ }
+
+ // TODO: Handle CharSequence instead of String
+ public static void logOnClickSuggestion(String before, String after, int position) {
+ if (sLogEnabled) {
+ String[] strings = new String[] {before, after, String.valueOf(position)};
+ sLatinImeLogger.sendLogToDropBox(ID_CLICKSUGGESTION, strings);
+ }
+ }
+
+ public static void logOnAutoSuggestion(String before, String after) {
+ if (sLogEnabled) {
+ String[] strings = new String[] {before, after};
+ synchronized (LatinImeLogger.class) {
+ sLastAutoSuggestBefore = before;
+ sLastAutoSuggestAfter = after;
+ }
+ sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTIONCANCELED, strings);
+ }
+ }
+
+ public static void logOnAutoSuggestionCanceled() {
+ if (sLogEnabled) {
+ if (sLastAutoSuggestBefore != null && sLastAutoSuggestAfter != null) {
+ String[] strings = new String[] {sLastAutoSuggestBefore, sLastAutoSuggestAfter};
+ sLatinImeLogger.sendLogToDropBox(ID_AUTOSUGGESTION, strings);
+ }
+ }
+ }
+
+ public static void logOnDelete(int length) {
+ if (sLogEnabled) {
+ sLatinImeLogger.sendLogToDropBox(ID_DELETE_COUNT, length);
+ }
+ }
+
+ public static void logOnInputChar(int length) {
+ if (sLogEnabled) {
+ sLatinImeLogger.sendLogToDropBox(ID_INPUT_COUNT, length);
+ }
+ }
+
+ private static class LogSerializer {
+ private static void appendWithLength(StringBuffer sb, String data) {
+ sb.append(data.length());
+ sb.append(SEPARATER);
+ sb.append(data);
+ sb.append(SEPARATER);
+ }
+
+ private static void appendLogEntry(StringBuffer sb, String time, String tag,
+ String[] data) {
+ if (data.length > 0) {
+ appendWithLength(sb, String.valueOf(data.length + 2));
+ appendWithLength(sb, time);
+ appendWithLength(sb, tag);
+ for (String s: data) {
+ appendWithLength(sb, s);
+ }
+ }
+ }
+
+ public static String createStringFromEntries(ArrayList<LogEntry> logs) {
+ StringBuffer sb = new StringBuffer();
+ for (LogEntry log: logs) {
+ appendLogEntry(sb, String.valueOf(log.mTime), String.valueOf(log.mTag), log.mData);
+ }
+ return sb.toString();
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java
index d056ceb16..d291af651 100644
--- a/java/src/com/android/inputmethod/latin/TextEntryState.java
+++ b/java/src/com/android/inputmethod/latin/TextEntryState.java
@@ -130,6 +130,7 @@ public class TextEntryState {
sTypedChars += typedWord.length();
sActualChars += actualWord.length();
sState = STATE_ACCEPTED_DEFAULT;
+ LatinImeLogger.logOnAutoSuggestion(typedWord.toString(), actualWord.toString());
}
public static void acceptedTyped(CharSequence typedWord) {
@@ -199,6 +200,7 @@ public class TextEntryState {
if (sState == STATE_ACCEPTED_DEFAULT) {
sState = STATE_UNDO_COMMIT;
sAutoSuggestUndoneCount++;
+ LatinImeLogger.logOnAutoSuggestionCanceled();
} else if (sState == STATE_UNDO_COMMIT) {
sState = STATE_IN_WORD;
}