From 2ba975afb9529a6574148596db190b939fbc3b3f Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Sat, 30 Jul 2011 10:19:51 +0900 Subject: Turn off the Settings key by default bug:5094401 Change-Id: Ieb42fdfa79be2afcfa6634e7404c17737ef6927d --- java/src/com/android/inputmethod/latin/Utils.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 6bdc0a857..23ef1a03c 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -546,11 +546,11 @@ public class Utils { } } - public static int getKeyboardMode(EditorInfo attribute) { - if (attribute == null) + public static int getKeyboardMode(EditorInfo editorInfo) { + if (editorInfo == null) return KeyboardId.MODE_TEXT; - final int inputType = attribute.inputType; + final int inputType = editorInfo.inputType; final int variation = inputType & InputType.TYPE_MASK_VARIATION; switch (inputType & InputType.TYPE_MASK_CLASS) { @@ -587,11 +587,11 @@ public class Utils { } public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo attribute) { - if (attribute == null) + EditorInfo editorInfo) { + if (editorInfo == null) return false; return containsInCsv(packageName != null ? packageName + "." + key : key, - attribute.privateImeOptions); + editorInfo.privateImeOptions); } /** -- cgit v1.2.3-83-g751a From 9351550dc6af7859e5280e16144c9386a37b976d Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Sun, 31 Jul 2011 11:28:15 +0900 Subject: Clean up revertLastWord() The "deleteChar" argument of this method is acutally always true in the current code path. Also, in this method, textToTheLeft virtually never has a punctuation letter as its initial character. This change is one of preparatory changes for bug:4983945. Change-Id: I531a32570a35634c21c1d74b2b461e40a1b7f660 --- .../com/android/inputmethod/latin/LatinIME.java | 101 +++++++++------------ java/src/com/android/inputmethod/latin/Utils.java | 12 +++ 2 files changed, 54 insertions(+), 59 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 225c7c899..97c222695 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -557,7 +557,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // If orientation changed while predicting, commit the change if (conf.orientation != mDisplayOrientation) { mHandler.startOrientationChanging(mDisplayWidth, mDisplayHeight); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); commitTyped(ic); if (ic != null) ic.finishComposingText(); // For voice input if (isShowingOptionDialog()) @@ -807,7 +807,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar setPunctuationSuggestions(); } TextEntryState.reset(); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.finishComposingText(); } @@ -1012,7 +1012,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar event.getAction(), event.getKeyCode(), event.getRepeatCount(), event.getDeviceId(), event.getScanCode(), KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_SHIFT_ON); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) ic.sendKeyEvent(newEvent); return true; @@ -1022,12 +1022,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return super.onKeyUp(keyCode, event); } - public void commitTyped(InputConnection inputConnection) { + public void commitTyped(final InputConnection ic) { if (!mHasUncommittedTypedChars) return; mHasUncommittedTypedChars = false; if (mComposingStringBuilder.length() > 0) { - if (inputConnection != null) { - inputConnection.commitText(mComposingStringBuilder, 1); + if (ic != null) { + ic.commitText(mComposingStringBuilder, 1); } mCommittedLength = mComposingStringBuilder.length(); TextEntryState.acceptedTyped(mComposingStringBuilder); @@ -1038,7 +1038,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public boolean getCurrentAutoCapsState() { - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); EditorInfo ei = getCurrentInputEditorInfo(); if (mSettingsValues.mAutoCap && ic != null && ei != null && ei.inputType != InputType.TYPE_NULL) { @@ -1062,25 +1062,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private static boolean canBeFollowedByPeriod(final int codePoint) { - // TODO: Check again whether there really ain't a better way to check this. - // TODO: This should probably be language-dependant... - return Character.isLetterOrDigit(codePoint) - || codePoint == Keyboard.CODE_SINGLE_QUOTE - || codePoint == Keyboard.CODE_DOUBLE_QUOTE - || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS - || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET - || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET - || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; - } - private void maybeDoubleSpace() { if (mCorrectionMode == Suggest.CORRECTION_NONE) return; final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 - && canBeFollowedByPeriod(lastThree.charAt(0)) + && Utils.canBeFollowedByPeriod(lastThree.charAt(0)) && lastThree.charAt(1) == Keyboard.CODE_SPACE && lastThree.charAt(2) == Keyboard.CODE_SPACE && mHandler.isAcceptingDoubleSpaces()) { @@ -1096,10 +1084,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private void maybeRemovePreviousPeriod(CharSequence text) { - final InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - + // "ic" must not null + private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { // When the text's first character is '.', remove the previous period // if there is one. CharSequence lastOne = ic.getTextBeforeCursor(1, 0); @@ -1238,12 +1224,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void onTextInput(CharSequence text) { mVoiceProxy.commitVoiceInput(); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic == null) return; mRecorrection.abortRecorrection(false); ic.beginBatchEdit(); commitTyped(ic); - maybeRemovePreviousPeriod(text); + maybeRemovePreviousPeriod(ic, text); ic.commitText(text, 1); ic.endBatchEdit(); mKeyboardSwitcher.updateShiftState(); @@ -1293,14 +1279,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar TextEntryState.backspace(); if (TextEntryState.isUndoCommit()) { - revertLastWord(deleteChar); + revertLastWord(ic); ic.endBatchEdit(); return; } if (justReplacedDoubleSpace) { - if (revertDoubleSpace()) { - ic.endBatchEdit(); - return; + if (revertDoubleSpace(ic)) { + ic.endBatchEdit(); + return; } } @@ -1315,7 +1301,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // different behavior only in the case of picking the first // suggestion (typed word). It's intentional to have made this // inconsistent with backspacing after selecting other suggestions. - revertLastWord(true /* deleteChar */); + revertLastWord(ic); } else { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); if (mDeleteCount > DELETE_ACCELERATE_AT) { @@ -1398,7 +1384,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mComposingStringBuilder.append((char) code); mWordComposer.add(code, keyCodes, x, y); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) { // If it's the first letter, make note of auto-caps state if (mWordComposer.size() == 1) { @@ -1663,15 +1649,15 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mSettingsValues.mWordSeparators); final boolean recorrecting = TextEntryState.isRecorrecting(); - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) { ic.beginBatchEdit(); } if (mApplicationSpecifiedCompletionOn && mApplicationSpecifiedCompletions != null && index >= 0 && index < mApplicationSpecifiedCompletions.length) { - CompletionInfo ci = mApplicationSpecifiedCompletions[index]; if (ic != null) { - ic.commitCompletion(ci); + final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; + ic.commitCompletion(completionInfo); } mCommittedLength = suggestion.length(); if (mCandidateView != null) { @@ -1783,10 +1769,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar * Commits the chosen word to the text field and saves it for later retrieval. */ private void commitBestWord(CharSequence bestWord) { - KeyboardSwitcher switcher = mKeyboardSwitcher; + final KeyboardSwitcher switcher = mKeyboardSwitcher; if (!switcher.isKeyboardAvailable()) return; - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic != null) { mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); SuggestedWords suggestedWords = mCandidateView.getSuggestions(); @@ -1878,7 +1864,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public boolean isCursorTouchingWord() { - InputConnection ic = getCurrentInputConnection(); + final InputConnection ic = getCurrentInputConnection(); if (ic == null) return false; CharSequence toLeft = ic.getTextBeforeCursor(1, 0); CharSequence toRight = ic.getTextAfterCursor(1, 0); @@ -1895,36 +1881,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return false; } - private boolean sameAsTextBeforeCursor(InputConnection ic, CharSequence text) { + // "ic" must not null + private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); return TextUtils.equals(text, beforeText); } - private void revertLastWord(boolean deleteChar) { + // "ic" must not null + private void revertLastWord(final InputConnection ic) { if (mHasUncommittedTypedChars || mComposingStringBuilder.length() <= 0) { sendDownUpKeyEvents(KeyEvent.KEYCODE_DEL); return; } - final InputConnection ic = getCurrentInputConnection(); - final CharSequence punctuation = ic.getTextBeforeCursor(1, 0); - if (deleteChar) ic.deleteSurroundingText(1, 0); - final CharSequence textToTheLeft = ic.getTextBeforeCursor(mCommittedLength, 0); - final int toDeleteLength = (!TextUtils.isEmpty(textToTheLeft) - && mSettingsValues.isWordSeparator(textToTheLeft.charAt(0))) - ? mCommittedLength - 1 : mCommittedLength; - ic.deleteSurroundingText(toDeleteLength, 0); - - // Re-insert punctuation only when the deleted character was word separator and the - // composing text wasn't equal to the auto-corrected text. - if (deleteChar - && !TextUtils.isEmpty(punctuation) - && mSettingsValues.isWordSeparator(punctuation.charAt(0)) - && !TextUtils.equals(mComposingStringBuilder, textToTheLeft)) { + final CharSequence separator = ic.getTextBeforeCursor(1, 0); + ic.deleteSurroundingText(mCommittedLength + 1 /* separator */, 0); + + // Re-insert "separator" only when the deleted character was word separator and the + // composing text wasn't equal to the auto-corrected text which can be found before + // the cursor. + if (!TextUtils.isEmpty(separator) + && mSettingsValues.isWordSeparator(separator.charAt(0)) + && !TextUtils.equals(mComposingStringBuilder, + ic.getTextBeforeCursor(mCommittedLength, 0))) { ic.commitText(mComposingStringBuilder, 1); TextEntryState.acceptedTyped(mComposingStringBuilder); - ic.commitText(punctuation, 1); - TextEntryState.typedCharacter(punctuation.charAt(0), true, + ic.commitText(separator, 1); + TextEntryState.typedCharacter(separator.charAt(0), true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); // Clear composing text mComposingStringBuilder.setLength(0); @@ -1937,9 +1920,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.postUpdateSuggestions(); } - private boolean revertDoubleSpace() { + // "ic" must not null + private boolean revertDoubleSpace(final InputConnection ic) { mHandler.cancelDoubleSpacesTimer(); - final InputConnection ic = getCurrentInputConnection(); // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 23ef1a03c..16a2b0e5f 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -190,6 +190,18 @@ public class Utils { } } + public static boolean canBeFollowedByPeriod(final int codePoint) { + // TODO: Check again whether there really ain't a better way to check this. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Keyboard.CODE_SINGLE_QUOTE + || codePoint == Keyboard.CODE_DOUBLE_QUOTE + || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS + || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET + || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; + } + /* package */ static class RingCharBuffer { private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; -- cgit v1.2.3-83-g751a From cadb2128f54b49be31bb4dc06374afe81ed028b7 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Sat, 6 Aug 2011 10:45:19 +0900 Subject: Fix issues with long-pressing the spacebar bug: 5114433 Change-Id: I18f2147724a08965147bafe93e11fc86c7c59d33 --- java/res/values/keycodes.xml | 2 +- .../com/android/inputmethod/keyboard/Keyboard.java | 3 +- .../keyboard/KeyboardActionListener.java | 6 ++++ .../inputmethod/keyboard/LatinKeyboardView.java | 10 ++++-- .../inputmethod/keyboard/PointerTracker.java | 2 ++ .../keyboard/PopupMiniKeyboardView.java | 2 ++ .../com/android/inputmethod/latin/LatinIME.java | 37 ++++++++++++---------- java/src/com/android/inputmethod/latin/Utils.java | 35 ++++++++++++-------- 8 files changed, 62 insertions(+), 35 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index ee345291a..59cc07531 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -27,5 +27,5 @@ -2 -5 -6 - -8 + -7 diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 518bc8e9e..f8e08b06a 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -79,8 +79,7 @@ public class Keyboard { public static final int CODE_CANCEL = -4; public static final int CODE_DELETE = -5; public static final int CODE_SETTINGS = -6; - public static final int CODE_SETTINGS_LONGPRESS = -7; - public static final int CODE_SHORTCUT = -8; + public static final int CODE_SHORTCUT = -7; // Code value representing the code is not specified. public static final int CODE_UNSPECIFIED = -99; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index 905f779c0..864091289 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -70,4 +70,10 @@ public interface KeyboardActionListener { * Called when user released a finger outside any key. */ public void onCancelInput(); + + /** + * Send a non-"code input" custom request to the listener. + * @return true if the request has been consumed, false otherwise. + */ + public boolean onCustomRequest(int requestCode); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 04096778b..dad37e728 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -23,6 +23,7 @@ import android.util.Log; import android.view.MotionEvent; import com.android.inputmethod.deprecated.VoiceProxy; +import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.Utils; @@ -99,9 +100,14 @@ public class LatinKeyboardView extends LatinKeyboardBaseView { } } if (primaryCode == Keyboard.CODE_SETTINGS || primaryCode == Keyboard.CODE_SPACE) { - tracker.onLongPressed(); // Both long pressing settings key and space key invoke IME switcher dialog. - return invokeOnKey(Keyboard.CODE_SETTINGS_LONGPRESS); + if (getKeyboardActionListener().onCustomRequest( + LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { + tracker.onLongPressed(); + return true; + } else { + return super.onLongPress(key, tracker); + } } else { return super.onLongPress(key, tracker); } diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index dc2d6e4b0..1f8119a0f 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -151,6 +151,8 @@ public class PointerTracker { public void onTextInput(CharSequence text) {} @Override public void onCancelInput() {} + @Override + public boolean onCustomRequest(int requestCode) { return false; } }; public static void init(boolean hasDistinctMultitouch, Context context) { diff --git a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java index dfaaa707c..fb932e3e8 100644 --- a/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/PopupMiniKeyboardView.java @@ -79,6 +79,8 @@ public class PopupMiniKeyboardView extends KeyboardView implements PopupPanel { public void onRelease(int primaryCode, boolean withSliding) { mParentKeyboardView.getKeyboardActionListener().onRelease(primaryCode, withSliding); } + @Override + public boolean onCustomRequest(int requestCode) { return false; } }; public PopupMiniKeyboardView(Context context, AttributeSet attrs) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 6c91c454c..5ccbf3fa2 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -430,8 +430,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public boolean postStartInputView(EditorInfo attribute) { if (hasMessages(MSG_CONFIRM_ORIENTATION_CHANGE) || hasMessages(MSG_START_INPUT_VIEW)) { removeMessages(MSG_START_INPUT_VIEW); - // Postpone onStartInputView 20ms afterward and see if orientation change has - // finished. + // Postpone onStartInputView by ACCUMULATE_START_INPUT_VIEW_DELAY and see if + // orientation change has finished. sendMessageDelayed(obtainMessage(MSG_START_INPUT_VIEW, attribute), ACCUMULATE_START_INPUT_VIEW_DELAY); return true; @@ -1152,25 +1152,33 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void onSettingsKeyPressed() { - if (isShowingOptionDialog()) - return; + if (isShowingOptionDialog()) return; if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { + } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, + false /* should exclude auxiliary subtypes */)) { showOptionsMenu(); } else { launchSettings(); } } - private void onSettingsKeyLongPressed() { - if (!isShowingOptionDialog()) { - if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm)) { + // Virtual codes representing custom requests. These are used in onCustomRequest() below. + public static final int CODE_SHOW_INPUT_METHOD_PICKER = 1; + + @Override + public boolean onCustomRequest(int requestCode) { + if (isShowingOptionDialog()) return false; + switch (requestCode) { + case CODE_SHOW_INPUT_METHOD_PICKER: + if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, + true /* should include auxiliary subtypes */)) { mImm.showInputMethodPicker(); - } else { - launchSettings(); + return true; } + return false; } + return false; } private boolean isShowingOptionDialog() { @@ -1214,9 +1222,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case Keyboard.CODE_SETTINGS: onSettingsKeyPressed(); break; - case Keyboard.CODE_SETTINGS_LONGPRESS: - onSettingsKeyLongPressed(); - break; case Keyboard.CODE_CAPSLOCK: switcher.toggleCapsLock(); break; @@ -2135,14 +2140,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } protected void launchSettings() { - launchSettings(Settings.class); + launchSettingsClass(Settings.class); } public void launchDebugSettings() { - launchSettings(DebugSettings.class); + launchSettingsClass(DebugSettings.class); } - protected void launchSettings(Class settingsClass) { + protected void launchSettingsClass(Class settingsClass) { handleClose(); Intent intent = new Intent(); intent.setClass(LatinIME.this, settingsClass); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 16a2b0e5f..c07793c33 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -111,35 +111,42 @@ public class Utils { } } - public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm) { + public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm, + boolean shouldIncludeAuxiliarySubtypes) { final List enabledImis = imm.getEnabledInputMethodList(); - // Filters out IMEs that have auxiliary subtypes only (including either implicitly or - // explicitly enabled ones). - final ArrayList filteredImis = - new ArrayList(); + // Number of the filtered IMEs + int filteredImisCount = 0; - outerloop: for (InputMethodInfoCompatWrapper imi : enabledImis) { // We can return true immediately after we find two or more filtered IMEs. - if (filteredImis.size() > 1) return true; + if (filteredImisCount > 1) return true; final List subtypes = imm.getEnabledInputMethodSubtypeList(imi, true); - // IMEs that have no subtypes should be included. + // IMEs that have no subtypes should be counted. if (subtypes.isEmpty()) { - filteredImis.add(imi); + ++filteredImisCount; continue; } - // IMEs that have one or more non-auxiliary subtypes should be included. + + int auxCount = 0; for (InputMethodSubtypeCompatWrapper subtype : subtypes) { - if (!subtype.isAuxiliary()) { - filteredImis.add(imi); - continue outerloop; + if (subtype.isAuxiliary()) { + ++auxCount; } } + final int nonAuxCount = subtypes.size() - auxCount; + + // IMEs that have one or more non-auxiliary subtypes should be counted. + // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary + // subtypes should be counted as well. + if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { + ++filteredImisCount; + continue; + } } - return filteredImis.size() > 1 + return filteredImisCount > 1 // imm.getEnabledInputMethodSubtypeList(null, false) will return the current IME's enabled // input method subtype (The current IME should be LatinIME.) || imm.getEnabledInputMethodSubtypeList(null, false).size() > 1; -- cgit v1.2.3-83-g751a From 11b7febc0bea46a6afb30d7fa040b841eadd7410 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Tue, 9 Aug 2011 19:50:21 +0900 Subject: Ellipsis for "Space" key for triggering the IME switcher bug:5136497 Change-Id: Iab7c68135500e9fed212521484090b52943550ca --- java/src/com/android/inputmethod/keyboard/Key.java | 10 ++++++++++ .../com/android/inputmethod/keyboard/KeyboardView.java | 3 ++- .../com/android/inputmethod/keyboard/LatinKeyboard.java | 15 +++++++++++++-- java/src/com/android/inputmethod/latin/LatinIME.java | 6 ++---- java/src/com/android/inputmethod/latin/Utils.java | 5 +++-- 5 files changed, 30 insertions(+), 9 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index 4cc0bba6a..397b7b16b 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -113,6 +113,8 @@ public class Key { private boolean mHighlightOn; /** Key is enabled and responds on press */ private boolean mEnabled = true; + /** Whether this key needs to show the "..." popup hint for special purposes */ + private boolean mNeedsSpecialPopupHint; // keyWidth constants private static final int KEYWIDTH_FILL_RIGHT = 0; @@ -402,6 +404,14 @@ public class Key { return (mLabelOption & LABEL_OPTION_HAS_POPUP_HINT) != 0; } + public void setNeedsSpecialPopupHint(boolean needsSpecialPopupHint) { + mNeedsSpecialPopupHint = needsSpecialPopupHint; + } + + public boolean needsSpecialPopupHint() { + return mNeedsSpecialPopupHint; + } + public boolean hasUppercaseLetter() { return (mLabelOption & LABEL_OPTION_HAS_UPPERCASE_LETTER) != 0; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index da3aa50c5..2df2994f6 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -657,7 +657,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } // Draw popup hint "..." at the bottom right corner of the key. - if (key.hasPopupHint() && key.mPopupCharacters != null && key.mPopupCharacters.length > 0) { + if ((key.hasPopupHint() && key.mPopupCharacters != null && key.mPopupCharacters.length > 0) + || key.needsSpecialPopupHint()) { paint.setTextSize(params.mKeyHintLetterSize); paint.setColor(params.mKeyHintLabelColor); paint.setTextAlign(Align.CENTER); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 3cba5295e..1b6f57b92 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -31,10 +31,12 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.keyboard.internal.KeyboardParams; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.Utils; import java.lang.ref.SoftReference; import java.util.Arrays; @@ -59,6 +61,7 @@ public class LatinKeyboard extends Keyboard { private float mSpacebarTextFadeFactor = 0.0f; private final HashMap> mSpaceDrawableCache = new HashMap>(); + private final boolean mIsSpacebarTriggeringPopupByLongPress; /* Shortcut key and its icons if available */ private final Key mShortcutKey; @@ -85,6 +88,9 @@ public class LatinKeyboard extends Keyboard { mShortcutKey = params.mShortcutKey; mEnabledShortcutIcon = (mShortcutKey != null) ? mShortcutKey.getIcon() : null; + final int longPressSpaceKeyTimeout = + mRes.getInteger(R.integer.config_long_press_space_key_timeout); + mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0); final TypedArray a = context.obtainStyledAttributes( null, R.styleable.LatinKeyboard, R.attr.latinKeyboardStyle, R.style.LatinKeyboard); @@ -179,8 +185,13 @@ public class LatinKeyboard extends Keyboard { } private void updateSpacebarForLocale(boolean isAutoCorrection) { - if (mSpaceKey == null) - return; + if (mSpaceKey == null) return; + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return; + // The "..." popup hint for triggering something by a long-pressing the spacebar + final boolean shouldShowInputMethodPicker = mIsSpacebarTriggeringPopupByLongPress + && Utils.hasMultipleEnabledIMEsOrSubtypes(imm, true /* include aux subtypes */); + mSpaceKey.setNeedsSpecialPopupHint(shouldShowInputMethodPicker); // If application locales are explicitly selected. if (mSubtypeSwitcher.needsToDisplayLanguage()) { mSpaceKey.setIcon(getSpaceDrawable( diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d74babf4f..c28e40d95 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1181,8 +1181,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isShowingOptionDialog()) return; if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, - false /* should exclude auxiliary subtypes */)) { + } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, false /* exclude aux subtypes */)) { showOptionsMenu(); } else { launchSettings(); @@ -1197,8 +1196,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isShowingOptionDialog()) return false; switch (requestCode) { case CODE_SHOW_INPUT_METHOD_PICKER: - if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, - true /* should include auxiliary subtypes */)) { + if (Utils.hasMultipleEnabledIMEsOrSubtypes(mImm, true /* include aux subtypes */)) { mImm.showInputMethodPicker(); return true; } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index c07793c33..1a6260a4e 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -111,8 +111,9 @@ public class Utils { } } - public static boolean hasMultipleEnabledIMEsOrSubtypes(InputMethodManagerCompatWrapper imm, - boolean shouldIncludeAuxiliarySubtypes) { + public static boolean hasMultipleEnabledIMEsOrSubtypes( + final InputMethodManagerCompatWrapper imm, + final boolean shouldIncludeAuxiliarySubtypes) { final List enabledImis = imm.getEnabledInputMethodList(); // Number of the filtered IMEs -- cgit v1.2.3-83-g751a From 6da8b74582b1c70cae02558c605c5a224329cf7a Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 19 Aug 2011 19:48:48 +0900 Subject: Move the dupes-removing method to the Utils class This is preparation for bug: 5175740 Change-Id: I18b2042317f740cb1e021d3dfbf90ecfbb1a1d37 --- .../src/com/android/inputmethod/latin/Suggest.java | 29 +----------------- java/src/com/android/inputmethod/latin/Utils.java | 34 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 28 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index c3caae448..e3cb6987a 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -404,7 +404,7 @@ public class Suggest implements Dictionary.WordCallback { if (typedWord != null) { mSuggestions.add(0, typedWordString); } - removeDupes(mSuggestions); + Utils.removeDupes(mSuggestions); if (DBG) { double normalizedScore = mAutoCorrection.getNormalizedScore(); @@ -431,33 +431,6 @@ public class Suggest implements Dictionary.WordCallback { return new SuggestedWords.Builder().addWords(mSuggestions, null); } - private static void removeDupes(final ArrayList suggestions) { - if (suggestions.size() < 2) return; - int i = 1; - // Don't cache suggestions.size(), since we may be removing items - while (i < suggestions.size()) { - final CharSequence cur = suggestions.get(i); - // Compare each candidate with each previous candidate - for (int j = 0; j < i; j++) { - CharSequence previous = suggestions.get(j); - if (TextUtils.equals(cur, previous)) { - removeFromSuggestions(suggestions, i); - i--; - break; - } - } - i++; - } - } - - private static void removeFromSuggestions(final ArrayList suggestions, - final int index) { - final CharSequence garbage = suggestions.remove(index); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } - } - public boolean hasAutoCorrection() { return mAutoCorrection.hasAutoCorrection(); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 1a6260a4e..36fbfd951 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -32,6 +32,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Process; import android.text.InputType; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; import android.view.inputmethod.EditorInfo; @@ -735,4 +736,37 @@ public class Utils { return retval; } } + + /** + * Remove duplicates from an array of strings. + * + * This method will always keep the first occurence of all strings at their position + * in the array, removing the subsequent ones. + */ + public static void removeDupes(final ArrayList suggestions) { + if (suggestions.size() < 2) return; + int i = 1; + // Don't cache suggestions.size(), since we may be removing items + while (i < suggestions.size()) { + final CharSequence cur = suggestions.get(i); + // Compare each candidate with each previous candidate + for (int j = 0; j < i; j++) { + CharSequence previous = suggestions.get(j); + if (TextUtils.equals(cur, previous)) { + removeFromSuggestions(suggestions, i); + i--; + break; + } + } + i++; + } + } + + private static void removeFromSuggestions(final ArrayList suggestions, + final int index) { + final CharSequence garbage = suggestions.remove(index); + if (garbage instanceof StringBuilder) { + StringBuilderPool.recycle((StringBuilder)garbage); + } + } } -- cgit v1.2.3-83-g751a From 57f05f44123fd458203a6f776f2ff904889d2616 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 24 Aug 2011 12:44:33 +0900 Subject: Move some static methods from SubtypeSwitcher to Utils Change-Id: I3ea8ffcdefcefaa82ae76a31bb65977009d8a040 --- .../languageswitcher/InputLanguageSelection.java | 5 ++-- .../deprecated/voice/RecognitionView.java | 3 ++- .../inputmethod/keyboard/LatinKeyboard.java | 6 ++--- .../android/inputmethod/latin/SubtypeSwitcher.java | 30 +--------------------- java/src/com/android/inputmethod/latin/Utils.java | 28 ++++++++++++++++++++ 5 files changed, 36 insertions(+), 36 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index e75559e62..7eb5acda8 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -21,7 +21,6 @@ import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SharedPreferencesCompat; -import com.android.inputmethod.latin.SubtypeSwitcher; import com.android.inputmethod.latin.Utils; import org.xmlpull.v1.XmlPullParserException; @@ -237,12 +236,12 @@ public class InputLanguageSelection extends PreferenceActivity { if (finalSize == 0) { preprocess[finalSize++] = - new LocaleEntry(SubtypeSwitcher.getFullDisplayName(l, false), l); + new LocaleEntry(Utils.getFullDisplayName(l, false), l); } else { if (s.equals("zz_ZZ")) { // ignore this locale } else { - final String displayName = SubtypeSwitcher.getFullDisplayName(l, false); + final String displayName = Utils.getFullDisplayName(l, false); preprocess[finalSize++] = new LocaleEntry(displayName, l); } } diff --git a/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java index dcb826e8f..71d15dc3d 100644 --- a/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java +++ b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java @@ -18,6 +18,7 @@ package com.android.inputmethod.deprecated.voice; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; +import com.android.inputmethod.latin.Utils; import android.content.Context; import android.content.res.Resources; @@ -221,7 +222,7 @@ public class RecognitionView { Locale locale = SubtypeSwitcher.getInstance().getInputLocale(); mLanguage.setVisibility(View.VISIBLE); - mLanguage.setText(SubtypeSwitcher.getFullDisplayName(locale, true)); + mLanguage.setText(Utils.getFullDisplayName(locale, true)); mPopupLayout.setBackgroundDrawable(mListeningBorder); break; diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java index 1b6f57b92..e18d3a6a8 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboard.java @@ -216,7 +216,7 @@ public class LatinKeyboard extends Keyboard { final Rect bounds = new Rect(); // Estimate appropriate language name text size to fit in maxTextWidth. - String language = SubtypeSwitcher.getFullDisplayName(locale, true); + String language = Utils.getFullDisplayName(locale, true); int textWidth = getTextWidth(paint, language, origTextSize, bounds); // Assuming text width and text size are proportional to each other. float textSize = origTextSize * Math.min(width / textWidth, 1.0f); @@ -228,7 +228,7 @@ public class LatinKeyboard extends Keyboard { final boolean useShortName; if (useMiddleName) { - language = SubtypeSwitcher.getMiddleDisplayLanguage(locale); + language = Utils.getMiddleDisplayLanguage(locale); textWidth = getTextWidth(paint, language, origTextSize, bounds); textSize = origTextSize * Math.min(width / textWidth, 1.0f); useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) @@ -238,7 +238,7 @@ public class LatinKeyboard extends Keyboard { } if (useShortName) { - language = SubtypeSwitcher.getShortDisplayLanguage(locale); + language = Utils.getShortDisplayLanguage(locale); textWidth = getTextWidth(paint, language, origTextSize, bounds); textSize = origTextSize * Math.min(width / textWidth, 1.0f); } diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index 0a391a77e..369b11c11 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -492,36 +492,8 @@ public class SubtypeSwitcher { KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken()); } - public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { - if (returnsNameInThisLocale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } else { - return toTitleCase(locale.getDisplayName(), locale); - } - } - - public static String getDisplayLanguage(Locale locale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } - - public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((Utils.constructLocaleFromString( - locale.getLanguage()).getDisplayLanguage(locale)), locale); - } - - public static String getShortDisplayLanguage(Locale locale) { - return toTitleCase(locale.getLanguage(), locale); - } - - private static String toTitleCase(String s, Locale locale) { - if (s.length() == 0) { - return s; - } - return s.toUpperCase(locale).charAt(0) + s.substring(1); - } - public String getInputLanguageName() { - return getDisplayLanguage(getInputLocale()); + return Utils.getDisplayLanguage(getInputLocale()); } ///////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 36fbfd951..ff051dcbb 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -769,4 +769,32 @@ public class Utils { StringBuilderPool.recycle((StringBuilder)garbage); } } + + public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { + if (returnsNameInThisLocale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } else { + return toTitleCase(locale.getDisplayName(), locale); + } + } + + public static String getDisplayLanguage(Locale locale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } + + public static String getMiddleDisplayLanguage(Locale locale) { + return toTitleCase((constructLocaleFromString( + locale.getLanguage()).getDisplayLanguage(locale)), locale); + } + + public static String getShortDisplayLanguage(Locale locale) { + return toTitleCase(locale.getLanguage(), locale); + } + + private static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + return s; + } + return s.toUpperCase(locale).charAt(0) + s.substring(1); + } } -- cgit v1.2.3-83-g751a From ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 26 Aug 2011 20:22:47 +0900 Subject: Move locale-related utility methods to LocaleUtils. Change-Id: I7e9e6e5bc4486d8618d0213b112308c3d305c15e --- .../languageswitcher/InputLanguageSelection.java | 5 ++- .../languageswitcher/LanguageSwitcher.java | 4 +- .../inputmethod/keyboard/KeyboardSwitcher.java | 5 ++- .../inputmethod/latin/BinaryDictionaryGetter.java | 4 +- .../inputmethod/latin/DictionaryFactory.java | 14 +++--- .../com/android/inputmethod/latin/LatinIME.java | 8 ++-- .../com/android/inputmethod/latin/LocaleUtils.java | 51 ++++++++++++++++++++++ .../com/android/inputmethod/latin/Settings.java | 6 +-- .../android/inputmethod/latin/SubtypeSwitcher.java | 2 +- java/src/com/android/inputmethod/latin/Utils.java | 34 +-------------- .../spellcheck/AndroidSpellCheckerService.java | 5 ++- .../inputmethod/latin/SubtypeLocaleTests.java | 4 +- 12 files changed, 82 insertions(+), 60 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index 7eb5acda8..b6e0ec9cf 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -18,6 +18,7 @@ package com.android.inputmethod.deprecated.languageswitcher; import com.android.inputmethod.keyboard.internal.KeyboardBuilder; import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SharedPreferencesCompat; @@ -155,7 +156,7 @@ public class InputLanguageSelection extends PreferenceActivity { private Pair hasDictionaryOrLayout(Locale locale) { if (locale == null) return new Pair(null, false); final Resources res = getResources(); - final Locale saveLocale = Utils.setSystemLocale(res, locale); + final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); final Long dictionaryId = DictionaryFactory.getDictionaryId(this, locale); boolean hasLayout = false; @@ -174,7 +175,7 @@ public class InputLanguageSelection extends PreferenceActivity { } catch (XmlPullParserException e) { } catch (IOException e) { } - Utils.setSystemLocale(res, saveLocale); + LocaleUtils.setSystemLocale(res, saveLocale); return new Pair(dictionaryId, hasLayout); } diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java index 1eedb5ee1..8070942d0 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/LanguageSwitcher.java @@ -18,9 +18,9 @@ package com.android.inputmethod.deprecated.languageswitcher; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SharedPreferencesCompat; -import com.android.inputmethod.latin.Utils; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; @@ -126,7 +126,7 @@ public class LanguageSwitcher { private void constructLocales() { mLocales.clear(); for (final String lang : mSelectedLanguageArray) { - final Locale locale = Utils.constructLocaleFromString(lang); + final Locale locale = LocaleUtils.constructLocaleFromString(lang); mLocales.add(locale); } } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index b1212f424..e43ae55a8 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -33,6 +33,7 @@ import com.android.inputmethod.keyboard.internal.ModifierKeyState; import com.android.inputmethod.keyboard.internal.ShiftKeyState; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; +import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.SubtypeSwitcher; @@ -258,11 +259,11 @@ public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceCha final SoftReference ref = mKeyboardCache.get(id); LatinKeyboard keyboard = (ref == null) ? null : ref.get(); if (keyboard == null) { - final Locale savedLocale = Utils.setSystemLocale(mResources, id.mLocale); + final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale); try { keyboard = new LatinKeyboard.Builder(mThemeContext).load(id).build(); } finally { - Utils.setSystemLocale(mResources, savedLocale); + LocaleUtils.setSystemLocale(mResources, savedLocale); } mKeyboardCache.put(id, new SoftReference(keyboard)); diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java index 360c944d2..5546d48c0 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionaryGetter.java @@ -157,9 +157,9 @@ class BinaryDictionaryGetter { private static AssetFileAddress loadFallbackResource(final Context context, final int fallbackResId, final Locale locale) { final Resources res = context.getResources(); - final Locale savedLocale = Utils.setSystemLocale(res, locale); + final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale); final AssetFileDescriptor afd = res.openRawResourceFd(fallbackResId); - Utils.setSystemLocale(res, savedLocale); + LocaleUtils.setSystemLocale(res, savedLocale); if (afd == null) { Log.e(TAG, "Found the resource but cannot read it. Is it compressed? resId=" diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 9642151d7..dfaad26bc 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -83,9 +83,9 @@ public class DictionaryFactory { try { final Resources res = context.getResources(); if (null != locale) { - final Locale savedLocale = Utils.setSystemLocale(res, locale); + final Locale savedLocale = LocaleUtils.setSystemLocale(res, locale); afd = res.openRawResourceFd(resId); - Utils.setSystemLocale(res, savedLocale); + LocaleUtils.setSystemLocale(res, savedLocale); } else { afd = res.openRawResourceFd(resId); } @@ -145,7 +145,7 @@ public class DictionaryFactory { */ public static boolean isDictionaryAvailable(Context context, Locale locale) { final Resources res = context.getResources(); - final Locale saveLocale = Utils.setSystemLocale(res, locale); + final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); final int resourceId = Utils.getMainDictionaryResourceId(res); final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); @@ -156,14 +156,14 @@ public class DictionaryFactory { /* Um, what can we do here exactly? */ } - Utils.setSystemLocale(res, saveLocale); + LocaleUtils.setSystemLocale(res, saveLocale); return hasDictionary; } // TODO: Do not use the size of the dictionary as an unique dictionary ID. - public static Long getDictionaryId(Context context, Locale locale) { + public static Long getDictionaryId(final Context context, final Locale locale) { final Resources res = context.getResources(); - final Locale saveLocale = Utils.setSystemLocale(res, locale); + final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); final int resourceId = Utils.getMainDictionaryResourceId(res); final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); @@ -175,7 +175,7 @@ public class DictionaryFactory { } catch (java.io.IOException e) { } - Utils.setSystemLocale(res, saveLocale); + LocaleUtils.setSystemLocale(res, saveLocale); return size; } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 552517bc8..229bf0f4c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -479,10 +479,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private void initSuggest() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); + final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); final Resources res = mResources; - final Locale savedLocale = Utils.setSystemLocale(res, keyboardLocale); + final Locale savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale); final ContactsDictionary oldContactsDictionary; if (mSuggest != null) { oldContactsDictionary = mSuggest.getContactsDictionary(); @@ -514,7 +514,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateCorrectionMode(); - Utils.setSystemLocale(res, savedLocale); + LocaleUtils.setSystemLocale(res, savedLocale); } /** @@ -551,7 +551,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /* package private */ void resetSuggestMainDict() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); - final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); + final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); int mainDicResId = Utils.getMainDictionaryResourceId(mResources); mSuggest.resetMainDict(this, mainDicResId, keyboardLocale); } diff --git a/java/src/com/android/inputmethod/latin/LocaleUtils.java b/java/src/com/android/inputmethod/latin/LocaleUtils.java index 054f1f9b8..efa9bfee3 100644 --- a/java/src/com/android/inputmethod/latin/LocaleUtils.java +++ b/java/src/com/android/inputmethod/latin/LocaleUtils.java @@ -16,8 +16,13 @@ package com.android.inputmethod.latin; +import android.content.res.Configuration; +import android.content.res.Resources; import android.text.TextUtils; +import java.util.HashMap; +import java.util.Locale; + /** * A class to help with handling Locales in string form. * @@ -30,6 +35,10 @@ public class LocaleUtils { private final static String TAG = LocaleUtils.class.getSimpleName(); + private LocaleUtils() { + // Intentional empty constructor for utility class. + } + // Locale match level constants. // A higher level of match is guaranteed to have a higher numerical value. // Some room is left within constants to add match cases that may arise necessary @@ -154,4 +163,46 @@ public class LocaleUtils { public static boolean isMatch(int level) { return LOCALE_MATCH <= level; } + + /** + * Sets the system locale for this process. + * + * @param res the resources to use. Pass current resources. + * @param newLocale the locale to change to. + * @return the old locale. + */ + public static Locale setSystemLocale(final Resources res, final Locale newLocale) { + final Configuration conf = res.getConfiguration(); + final Locale saveLocale = conf.locale; + conf.locale = newLocale; + res.updateConfiguration(conf, res.getDisplayMetrics()); + return saveLocale; + } + + private static final HashMap sLocaleCache = new HashMap(); + + /** + * Creates a locale from a string specification. + */ + public static Locale constructLocaleFromString(final String localeStr) { + if (localeStr == null) + return null; + synchronized (sLocaleCache) { + if (sLocaleCache.containsKey(localeStr)) + return sLocaleCache.get(localeStr); + Locale retval = null; + String[] localeParams = localeStr.split("_", 3); + if (localeParams.length == 1) { + retval = new Locale(localeParams[0]); + } else if (localeParams.length == 2) { + retval = new Locale(localeParams[0], localeParams[1]); + } else if (localeParams.length == 3) { + retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); + } + if (retval != null) { + sLocaleCache.put(localeStr, retval); + } + return retval; + } + } } diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 87a713f5c..a5eed9015 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -128,8 +128,8 @@ public class Settings extends InputMethodSettingsActivity final Resources res = context.getResources(); final Locale savedLocale; if (null != localeStr) { - final Locale keyboardLocale = Utils.constructLocaleFromString(localeStr); - savedLocale = Utils.setSystemLocale(res, keyboardLocale); + final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); + savedLocale = LocaleUtils.setSystemLocale(res, keyboardLocale); } else { savedLocale = null; } @@ -191,7 +191,7 @@ public class Settings extends InputMethodSettingsActivity mVoiceKeyEnabled = voiceMode != null && !voiceMode.equals(voiceModeOff); mVoiceKeyOnMain = voiceMode != null && voiceMode.equals(voiceModeMain); - Utils.setSystemLocale(res, savedLocale); + LocaleUtils.setSystemLocale(res, savedLocale); } public boolean isSuggestedPunctuation(int code) { diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index d969e39eb..87d854940 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -267,7 +267,7 @@ public class SubtypeSwitcher { // "en" --> language: en // "" --> the system locale if (!TextUtils.isEmpty(inputLocaleStr)) { - mInputLocale = Utils.constructLocaleFromString(inputLocaleStr); + mInputLocale = LocaleUtils.constructLocaleFromString(inputLocaleStr); mInputLocaleStr = inputLocaleStr; } else { mInputLocale = mSystemLocale; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index ff051dcbb..60a4cfb38 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -705,38 +705,6 @@ public class Utils { return (int) (dip * scale + 0.5); } - public static Locale setSystemLocale(Resources res, Locale newLocale) { - final Configuration conf = res.getConfiguration(); - final Locale saveLocale = conf.locale; - conf.locale = newLocale; - res.updateConfiguration(conf, res.getDisplayMetrics()); - return saveLocale; - } - - private static final HashMap sLocaleCache = new HashMap(); - - public static Locale constructLocaleFromString(String localeStr) { - if (localeStr == null) - return null; - synchronized (sLocaleCache) { - if (sLocaleCache.containsKey(localeStr)) - return sLocaleCache.get(localeStr); - Locale retval = null; - String[] localeParams = localeStr.split("_", 3); - if (localeParams.length == 1) { - retval = new Locale(localeParams[0]); - } else if (localeParams.length == 2) { - retval = new Locale(localeParams[0], localeParams[1]); - } else if (localeParams.length == 3) { - retval = new Locale(localeParams[0], localeParams[1], localeParams[2]); - } - if (retval != null) { - sLocaleCache.put(localeStr, retval); - } - return retval; - } - } - /** * Remove duplicates from an array of strings. * @@ -783,7 +751,7 @@ public class Utils { } public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((constructLocaleFromString( + return toTitleCase((LocaleUtils.constructLocaleFromString( locale.getLanguage()).getDisplayLanguage(locale)), locale); } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 502ebb52a..3244bcc65 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -33,6 +33,7 @@ import com.android.inputmethod.latin.Dictionary.DataType; import com.android.inputmethod.latin.Dictionary.WordCallback; import com.android.inputmethod.latin.DictionaryCollection; import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.UserDictionary; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WordComposer; @@ -139,7 +140,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private DictionaryPool getDictionaryPool(final String locale) { DictionaryPool pool = mDictionaryPools.get(locale); if (null == pool) { - final Locale localeObject = Utils.constructLocaleFromString(locale); + final Locale localeObject = LocaleUtils.constructLocaleFromString(locale); pool = new DictionaryPool(POOL_SIZE, this, localeObject); mDictionaryPools.put(locale, pool); } @@ -172,7 +173,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { public void onCreate() { final String localeString = getLocale(); mDictionaryPool = getDictionaryPool(localeString); - mLocale = Utils.constructLocaleFromString(localeString); + mLocale = LocaleUtils.constructLocaleFromString(localeString); } // Note : this must be reentrant diff --git a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java index d102aa4d1..fec3e8ee1 100644 --- a/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java +++ b/tests/src/com/android/inputmethod/latin/SubtypeLocaleTests.java @@ -16,7 +16,7 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.LocaleUtils; import android.content.Context; import android.content.res.Resources; @@ -77,7 +77,7 @@ public class SubtypeLocaleTests extends AndroidTestCase { int failedCount = 0; for (final InputMethodSubtype subtype : mKeyboardSubtypes) { final String localeCode = subtype.getLocale(); - final Locale locale = Utils.constructLocaleFromString(localeCode); + final Locale locale = LocaleUtils.constructLocaleFromString(localeCode); // The locale name which will be displayed on spacebar. For example 'English (US)' or // 'Francais (Canada)'. (c=\u008d) final String displayName = SubtypeLocale.getFullDisplayName(locale); -- cgit v1.2.3-83-g751a From 913e2aeef26f172d500a4ebfc644b5f47778841a Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 1 Sep 2011 14:54:28 +0900 Subject: Rename CandidateView to SuggestionsView Change-Id: I6480cdf025f065130e1969899b259a243e7a11be --- java/res/drawable-hdpi/btn_candidate_pressed.9.png | Bin 1234 -> 0 bytes .../res/drawable-hdpi/btn_suggestion_pressed.9.png | Bin 0 -> 1234 bytes .../candidate_feedback_background.9.png | Bin 1607 -> 0 bytes .../suggestion_feedback_background.9.png | Bin 0 -> 1607 bytes java/res/drawable-mdpi/btn_candidate_pressed.9.png | Bin 11006 -> 0 bytes .../res/drawable-mdpi/btn_suggestion_pressed.9.png | Bin 0 -> 11006 bytes .../candidate_feedback_background.9.png | Bin 1182 -> 0 bytes .../suggestion_feedback_background.9.png | Bin 0 -> 1182 bytes .../res/drawable-xhdpi/btn_candidate_pressed.9.png | Bin 1266 -> 0 bytes .../drawable-xhdpi/btn_suggestion_pressed.9.png | Bin 0 -> 1266 bytes .../candidate_feedback_background.9.png | Bin 1676 -> 0 bytes .../suggestion_feedback_background.9.png | Bin 0 -> 1676 bytes java/res/drawable/btn_candidate.xml | 27 - java/res/drawable/btn_candidate_ics.xml | 27 - java/res/drawable/btn_suggestion.xml | 27 + java/res/drawable/btn_suggestion_ics.xml | 27 + java/res/layout/candidate_divider.xml | 27 - java/res/layout/candidate_info.xml | 27 - java/res/layout/candidate_preview.xml | 28 - java/res/layout/candidate_word.xml | 36 - java/res/layout/candidates_strip.xml | 37 - java/res/layout/input_view.xml | 47 +- java/res/layout/more_suggestions.xml | 2 +- java/res/layout/suggestion_divider.xml | 27 + java/res/layout/suggestion_info.xml | 27 + java/res/layout/suggestion_preview.xml | 28 + java/res/layout/suggestion_word.xml | 36 + java/res/layout/suggestions_strip.xml | 37 + java/res/values-land/dimens.xml | 5 +- java/res/values-sw600dp-land/dimens.xml | 2 +- java/res/values-sw600dp/dimens.xml | 10 +- java/res/values-sw768dp-land/dimens.xml | 2 +- java/res/values-sw768dp/dimens.xml | 12 +- java/res/values/attrs.xml | 8 +- java/res/values/config.xml | 4 +- java/res/values/dimens.xml | 17 +- java/res/values/donottranslate.xml | 7 - java/res/values/strings.xml | 6 +- java/res/values/styles.xml | 18 +- java/res/values/themes-basic-highcontrast.xml | 2 +- java/res/values/themes-basic.xml | 2 +- java/res/values/themes-gingerbread.xml | 2 +- java/res/values/themes-ics.xml | 2 +- java/res/values/themes-stone-bold.xml | 2 +- java/res/values/themes-stone.xml | 2 +- .../deprecated/recorrection/Recorrection.java | 26 +- .../android/inputmethod/latin/AutoCorrection.java | 10 +- .../android/inputmethod/latin/CandidateView.java | 819 --------------------- .../com/android/inputmethod/latin/LatinIME.java | 107 +-- .../android/inputmethod/latin/MoreSuggestions.java | 10 +- .../android/inputmethod/latin/SuggestionsView.java | 819 +++++++++++++++++++++ java/src/com/android/inputmethod/latin/Utils.java | 26 +- 52 files changed, 1178 insertions(+), 1209 deletions(-) delete mode 100644 java/res/drawable-hdpi/btn_candidate_pressed.9.png create mode 100644 java/res/drawable-hdpi/btn_suggestion_pressed.9.png delete mode 100644 java/res/drawable-hdpi/candidate_feedback_background.9.png create mode 100644 java/res/drawable-hdpi/suggestion_feedback_background.9.png delete mode 100644 java/res/drawable-mdpi/btn_candidate_pressed.9.png create mode 100644 java/res/drawable-mdpi/btn_suggestion_pressed.9.png delete mode 100644 java/res/drawable-mdpi/candidate_feedback_background.9.png create mode 100644 java/res/drawable-mdpi/suggestion_feedback_background.9.png delete mode 100644 java/res/drawable-xhdpi/btn_candidate_pressed.9.png create mode 100644 java/res/drawable-xhdpi/btn_suggestion_pressed.9.png delete mode 100644 java/res/drawable-xhdpi/candidate_feedback_background.9.png create mode 100644 java/res/drawable-xhdpi/suggestion_feedback_background.9.png delete mode 100644 java/res/drawable/btn_candidate.xml delete mode 100644 java/res/drawable/btn_candidate_ics.xml create mode 100644 java/res/drawable/btn_suggestion.xml create mode 100644 java/res/drawable/btn_suggestion_ics.xml delete mode 100644 java/res/layout/candidate_divider.xml delete mode 100644 java/res/layout/candidate_info.xml delete mode 100644 java/res/layout/candidate_preview.xml delete mode 100644 java/res/layout/candidate_word.xml delete mode 100644 java/res/layout/candidates_strip.xml create mode 100644 java/res/layout/suggestion_divider.xml create mode 100644 java/res/layout/suggestion_info.xml create mode 100644 java/res/layout/suggestion_preview.xml create mode 100644 java/res/layout/suggestion_word.xml create mode 100644 java/res/layout/suggestions_strip.xml delete mode 100644 java/src/com/android/inputmethod/latin/CandidateView.java create mode 100644 java/src/com/android/inputmethod/latin/SuggestionsView.java (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/drawable-hdpi/btn_candidate_pressed.9.png b/java/res/drawable-hdpi/btn_candidate_pressed.9.png deleted file mode 100644 index 7acceaee7..000000000 Binary files a/java/res/drawable-hdpi/btn_candidate_pressed.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/btn_suggestion_pressed.9.png b/java/res/drawable-hdpi/btn_suggestion_pressed.9.png new file mode 100644 index 000000000..7acceaee7 Binary files /dev/null and b/java/res/drawable-hdpi/btn_suggestion_pressed.9.png differ diff --git a/java/res/drawable-hdpi/candidate_feedback_background.9.png b/java/res/drawable-hdpi/candidate_feedback_background.9.png deleted file mode 100644 index 16499002e..000000000 Binary files a/java/res/drawable-hdpi/candidate_feedback_background.9.png and /dev/null differ diff --git a/java/res/drawable-hdpi/suggestion_feedback_background.9.png b/java/res/drawable-hdpi/suggestion_feedback_background.9.png new file mode 100644 index 000000000..16499002e Binary files /dev/null and b/java/res/drawable-hdpi/suggestion_feedback_background.9.png differ diff --git a/java/res/drawable-mdpi/btn_candidate_pressed.9.png b/java/res/drawable-mdpi/btn_candidate_pressed.9.png deleted file mode 100644 index 02b4e9a53..000000000 Binary files a/java/res/drawable-mdpi/btn_candidate_pressed.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/btn_suggestion_pressed.9.png b/java/res/drawable-mdpi/btn_suggestion_pressed.9.png new file mode 100644 index 000000000..02b4e9a53 Binary files /dev/null and b/java/res/drawable-mdpi/btn_suggestion_pressed.9.png differ diff --git a/java/res/drawable-mdpi/candidate_feedback_background.9.png b/java/res/drawable-mdpi/candidate_feedback_background.9.png deleted file mode 100644 index 2a80f096d..000000000 Binary files a/java/res/drawable-mdpi/candidate_feedback_background.9.png and /dev/null differ diff --git a/java/res/drawable-mdpi/suggestion_feedback_background.9.png b/java/res/drawable-mdpi/suggestion_feedback_background.9.png new file mode 100644 index 000000000..2a80f096d Binary files /dev/null and b/java/res/drawable-mdpi/suggestion_feedback_background.9.png differ diff --git a/java/res/drawable-xhdpi/btn_candidate_pressed.9.png b/java/res/drawable-xhdpi/btn_candidate_pressed.9.png deleted file mode 100644 index 41e126a73..000000000 Binary files a/java/res/drawable-xhdpi/btn_candidate_pressed.9.png and /dev/null differ diff --git a/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png b/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png new file mode 100644 index 000000000..41e126a73 Binary files /dev/null and b/java/res/drawable-xhdpi/btn_suggestion_pressed.9.png differ diff --git a/java/res/drawable-xhdpi/candidate_feedback_background.9.png b/java/res/drawable-xhdpi/candidate_feedback_background.9.png deleted file mode 100644 index 0ec90e5ea..000000000 Binary files a/java/res/drawable-xhdpi/candidate_feedback_background.9.png and /dev/null differ diff --git a/java/res/drawable-xhdpi/suggestion_feedback_background.9.png b/java/res/drawable-xhdpi/suggestion_feedback_background.9.png new file mode 100644 index 000000000..0ec90e5ea Binary files /dev/null and b/java/res/drawable-xhdpi/suggestion_feedback_background.9.png differ diff --git a/java/res/drawable/btn_candidate.xml b/java/res/drawable/btn_candidate.xml deleted file mode 100644 index efcee9f54..000000000 --- a/java/res/drawable/btn_candidate.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - diff --git a/java/res/drawable/btn_candidate_ics.xml b/java/res/drawable/btn_candidate_ics.xml deleted file mode 100644 index e4257e327..000000000 --- a/java/res/drawable/btn_candidate_ics.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - diff --git a/java/res/drawable/btn_suggestion.xml b/java/res/drawable/btn_suggestion.xml new file mode 100644 index 000000000..cde12fe55 --- /dev/null +++ b/java/res/drawable/btn_suggestion.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/java/res/drawable/btn_suggestion_ics.xml b/java/res/drawable/btn_suggestion_ics.xml new file mode 100644 index 000000000..e4257e327 --- /dev/null +++ b/java/res/drawable/btn_suggestion_ics.xml @@ -0,0 +1,27 @@ + + + + + + diff --git a/java/res/layout/candidate_divider.xml b/java/res/layout/candidate_divider.xml deleted file mode 100644 index dc5e77966..000000000 --- a/java/res/layout/candidate_divider.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - diff --git a/java/res/layout/candidate_info.xml b/java/res/layout/candidate_info.xml deleted file mode 100644 index a364d46aa..000000000 --- a/java/res/layout/candidate_info.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - diff --git a/java/res/layout/candidate_preview.xml b/java/res/layout/candidate_preview.xml deleted file mode 100644 index 32705c996..000000000 --- a/java/res/layout/candidate_preview.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - diff --git a/java/res/layout/candidate_word.xml b/java/res/layout/candidate_word.xml deleted file mode 100644 index b711e8f29..000000000 --- a/java/res/layout/candidate_word.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - diff --git a/java/res/layout/candidates_strip.xml b/java/res/layout/candidates_strip.xml deleted file mode 100644 index fdb13f73e..000000000 --- a/java/res/layout/candidates_strip.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - diff --git a/java/res/layout/input_view.xml b/java/res/layout/input_view.xml index 821082f91..328469517 100644 --- a/java/res/layout/input_view.xml +++ b/java/res/layout/input_view.xml @@ -25,55 +25,34 @@ android:layout_width="match_parent" android:layout_height="wrap_content" > - + - + style="?attr/suggestionsViewStyle" /> - - - - - - diff --git a/java/res/layout/suggestion_divider.xml b/java/res/layout/suggestion_divider.xml new file mode 100644 index 000000000..e38a725b1 --- /dev/null +++ b/java/res/layout/suggestion_divider.xml @@ -0,0 +1,27 @@ + + + + diff --git a/java/res/layout/suggestion_info.xml b/java/res/layout/suggestion_info.xml new file mode 100644 index 000000000..a364d46aa --- /dev/null +++ b/java/res/layout/suggestion_info.xml @@ -0,0 +1,27 @@ + + + + diff --git a/java/res/layout/suggestion_preview.xml b/java/res/layout/suggestion_preview.xml new file mode 100644 index 000000000..3c026ae0e --- /dev/null +++ b/java/res/layout/suggestion_preview.xml @@ -0,0 +1,28 @@ + + + + diff --git a/java/res/layout/suggestion_word.xml b/java/res/layout/suggestion_word.xml new file mode 100644 index 000000000..d64cacf04 --- /dev/null +++ b/java/res/layout/suggestion_word.xml @@ -0,0 +1,36 @@ + + + + diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml new file mode 100644 index 000000000..9252017b4 --- /dev/null +++ b/java/res/layout/suggestions_strip.xml @@ -0,0 +1,37 @@ + + + + + + + + + diff --git a/java/res/values-land/dimens.xml b/java/res/values-land/dimens.xml index 4bf0e2092..322b6a63b 100644 --- a/java/res/values-land/dimens.xml +++ b/java/res/values-land/dimens.xml @@ -58,10 +58,9 @@ 0.01in - 36dip + 36dip 36dip - 160sp - 63dip + 160sp 0.336in diff --git a/java/res/values-sw600dp-land/dimens.xml b/java/res/values-sw600dp-land/dimens.xml index 1d26338c5..f1715af64 100644 --- a/java/res/values-sw600dp-land/dimens.xml +++ b/java/res/values-sw600dp-land/dimens.xml @@ -50,5 +50,5 @@ 34% 29% - 40.0mm + 40.0mm diff --git a/java/res/values-sw600dp/dimens.xml b/java/res/values-sw600dp/dimens.xml index 6ce23cc70..6955736b3 100644 --- a/java/res/values-sw600dp/dimens.xml +++ b/java/res/values-sw600dp/dimens.xml @@ -66,10 +66,10 @@ 15.0mm 0.05in - 44dip + 44dip 44dip - 15.0mm - 0.3in - 12dip - 22dip + 15.0mm + 0.3in + 12dip + 22dip diff --git a/java/res/values-sw768dp-land/dimens.xml b/java/res/values-sw768dp-land/dimens.xml index 0cfdffddd..7303ea1e7 100644 --- a/java/res/values-sw768dp-land/dimens.xml +++ b/java/res/values-sw768dp-land/dimens.xml @@ -58,5 +58,5 @@ 26.5mm 0.05in - 40.0mm + 40.0mm diff --git a/java/res/values-sw768dp/dimens.xml b/java/res/values-sw768dp/dimens.xml index 9b307e6f3..7db1df7b4 100644 --- a/java/res/values-sw768dp/dimens.xml +++ b/java/res/values-sw768dp/dimens.xml @@ -69,11 +69,11 @@ 15.0mm 0.05in - 44dip + 44dip 44dip - 200sp - 15.0mm - 46dip - 8dip - 22dip + 200sp + 15.0mm + 46dip + 8dip + 22dip diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml index 9d3426842..fa6b2eb39 100644 --- a/java/res/values/attrs.xml +++ b/java/res/values/attrs.xml @@ -30,7 +30,7 @@ - + @@ -112,7 +112,7 @@ - + @@ -122,8 +122,8 @@ - - + + diff --git a/java/res/values/config.xml b/java/res/values/config.xml index 923e37d85..1ffbbacbe 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -30,11 +30,11 @@ true true - true + at input history to suggest a hopefully helpful suggestions for the next word? --> false true false diff --git a/java/res/values/dimens.xml b/java/res/values/dimens.xml index b7609a4ac..bd8c1565a 100644 --- a/java/res/values/dimens.xml +++ b/java/res/values/dimens.xml @@ -76,19 +76,18 @@ 80sp 0.05in - 40dip + 40dip 12dip 40dip 0.2in 12% - 200sp - 63dip - 0dip - 44dip - 6dip - 18dip - 3 - 36 + 200sp + 0dip + 44dip + 6dip + 18dip + 3 + 36 diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 5cd995be9..228380da7 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -44,13 +44,6 @@ \uff0a\uff03 - - \u2502 - - \u25bc - - \u25b2 - 0 diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 2a3d705b0..fa80519f7 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -99,11 +99,11 @@ Spacebar and punctuation automatically correct mistyped words Off - + Modest - + Aggressive - + Very aggressive diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 4cc2a5306..17b3d14ab 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -88,21 +88,21 @@ @drawable/keyboard_suggest_strip diff --git a/java/res/values/themes-basic.xml b/java/res/values/themes-basic.xml index 7288dbacb..ff7f9ed35 100644 --- a/java/res/values/themes-basic.xml +++ b/java/res/values/themes-basic.xml @@ -25,6 +25,6 @@ @style/SuggestionsPaneViewStyle @style/SuggestionBackgroundStyle @style/SuggestionPreviewBackgroundStyle - @style/CandidateViewStyle + @style/SuggestionsViewStyle diff --git a/java/res/values/themes-gingerbread.xml b/java/res/values/themes-gingerbread.xml index 5b62378f6..af91c3bed 100644 --- a/java/res/values/themes-gingerbread.xml +++ b/java/res/values/themes-gingerbread.xml @@ -25,6 +25,6 @@ @style/SuggestionsPaneViewStyle @style/SuggestionBackgroundStyle @style/SuggestionPreviewBackgroundStyle - @style/CandidateViewStyle + @style/SuggestionsViewStyle diff --git a/java/res/values/themes-ics.xml b/java/res/values/themes-ics.xml index 597d87b4c..341afcc53 100644 --- a/java/res/values/themes-ics.xml +++ b/java/res/values/themes-ics.xml @@ -25,6 +25,6 @@ @style/SuggestionsPaneViewStyle.IceCreamSandwich @style/SuggestionBackgroundStyle.IceCreamSandwich @style/SuggestionPreviewBackgroundStyle.IceCreamSandwich - @style/CandidateViewStyle.IceCreamSandwich + @style/SuggestionsViewStyle.IceCreamSandwich diff --git a/java/res/values/themes-stone-bold.xml b/java/res/values/themes-stone-bold.xml index ff7107d32..915f2263e 100644 --- a/java/res/values/themes-stone-bold.xml +++ b/java/res/values/themes-stone-bold.xml @@ -25,6 +25,6 @@ @style/SuggestionsPaneViewStyle @style/SuggestionBackgroundStyle @style/SuggestionPreviewBackgroundStyle - @style/CandidateViewStyle + @style/SuggestionsViewStyle diff --git a/java/res/values/themes-stone.xml b/java/res/values/themes-stone.xml index 35390d111..6d5b9dbae 100644 --- a/java/res/values/themes-stone.xml +++ b/java/res/values/themes-stone.xml @@ -25,6 +25,6 @@ @style/SuggestionsPaneViewStyle @style/SuggestionBackgroundStyle @style/SuggestionPreviewBackgroundStyle - @style/CandidateViewStyle + @style/SuggestionsViewStyle diff --git a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java index bf2512d7b..75efa52f2 100644 --- a/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java +++ b/java/src/com/android/inputmethod/deprecated/recorrection/Recorrection.java @@ -16,28 +16,28 @@ package com.android.inputmethod.deprecated.recorrection; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.text.TextUtils; +import android.view.inputmethod.ExtractedText; +import android.view.inputmethod.ExtractedTextRequest; +import android.view.inputmethod.InputConnection; + import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.deprecated.VoiceProxy; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.latin.AutoCorrection; -import com.android.inputmethod.latin.CandidateView; import com.android.inputmethod.latin.EditingUtils; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.Settings; import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords; +import com.android.inputmethod.latin.SuggestionsView; import com.android.inputmethod.latin.TextEntryState; import com.android.inputmethod.latin.WordComposer; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.text.TextUtils; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; -import android.view.inputmethod.InputConnection; - import java.util.ArrayList; /** @@ -107,7 +107,7 @@ public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeL } public void updateRecorrectionSelection(KeyboardSwitcher keyboardSwitcher, - CandidateView candidateView, int candidatesStart, int candidatesEnd, + SuggestionsView suggestionsView, int candidatesStart, int candidatesEnd, int newSelStart, int newSelEnd, int oldSelStart, int lastSelectionStart, int lastSelectionEnd, boolean hasUncommittedTypedChars) { if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return; @@ -127,7 +127,7 @@ public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeL // If showing the "touch again to save" hint, do not replace it. Else, // show the bigrams if we are at the end of the text, punctuation // otherwise. - if (candidateView != null && !candidateView.isShowingAddToDictionaryHint()) { + if (suggestionsView != null && !suggestionsView.isShowingAddToDictionaryHint()) { InputConnection ic = mService.getCurrentInputConnection(); if (null == ic || !TextUtils.isEmpty(ic.getTextAfterCursor(1, 0))) { if (!mService.isShowingPunctuationList()) { @@ -219,13 +219,13 @@ public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeL } public void fetchAndDisplayRecorrectionSuggestions(VoiceProxy voiceProxy, - CandidateView candidateView, Suggest suggest, KeyboardSwitcher keyboardSwitcher, + SuggestionsView suggestionsView, Suggest suggest, KeyboardSwitcher keyboardSwitcher, WordComposer word, boolean hasUncommittedTypedChars, int lastSelectionStart, int lastSelectionEnd, String wordSeparators) { if (!InputConnectionCompatUtils.RECORRECTION_SUPPORTED) return; if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED || !mRecorrectionEnabled) return; voiceProxy.setShowingVoiceSuggestions(false); - if (candidateView != null && candidateView.isShowingAddToDictionaryHint()) { + if (suggestionsView != null && suggestionsView.isShowingAddToDictionaryHint()) { return; } InputConnection ic = mService.getCurrentInputConnection(); @@ -260,7 +260,7 @@ public class Recorrection implements SharedPreferences.OnSharedPreferenceChangeL if (SuggestionSpanUtils.SUGGESTION_SPAN_IS_SUPPORTED) return; if (force || TextEntryState.isRecorrecting()) { TextEntryState.onAbortRecorrection(); - mService.setCandidatesViewShown(mService.isCandidateStripVisible()); + mService.setCandidatesViewShown(mService.isSuggestionsStripVisible()); mService.getCurrentInputConnection().finishComposingText(); mService.clearSuggestions(); } diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index d3119792c..e6ae2c5c7 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -119,15 +119,15 @@ public class AutoCorrection { if (wordComposer.size() > 1 && (correctionMode == Suggest.CORRECTION_FULL || correctionMode == Suggest.CORRECTION_FULL_BIGRAM) && typedWord != null && suggestions.size() > 0 && sortedScores.length > 0) { - final CharSequence autoCorrectionCandidate = suggestions.get(0); - final int autoCorrectionCandidateScore = sortedScores[0]; + final CharSequence autoCorrectionSuggestion = suggestions.get(0); + final int autoCorrectionSuggestionScore = sortedScores[0]; // TODO: when the normalized score of the first suggestion is nearly equals to // the normalized score of the second suggestion, behave less aggressive. mNormalizedScore = Utils.calcNormalizedScore( - typedWord,autoCorrectionCandidate, autoCorrectionCandidateScore); + typedWord,autoCorrectionSuggestion, autoCorrectionSuggestionScore); if (DBG) { - Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionCandidate + "," - + autoCorrectionCandidateScore + ", " + mNormalizedScore + Log.d(TAG, "Normalized " + typedWord + "," + autoCorrectionSuggestion + "," + + autoCorrectionSuggestionScore + ", " + mNormalizedScore + "(" + autoCorrectionThreshold + ")"); } if (mNormalizedScore >= autoCorrectionThreshold) { diff --git a/java/src/com/android/inputmethod/latin/CandidateView.java b/java/src/com/android/inputmethod/latin/CandidateView.java deleted file mode 100644 index fe48f0bc1..000000000 --- a/java/src/com/android/inputmethod/latin/CandidateView.java +++ /dev/null @@ -1,819 +0,0 @@ -/* - * 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.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Color; -import android.graphics.Typeface; -import android.graphics.drawable.Drawable; -import android.os.Message; -import android.os.SystemClock; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.Spanned; -import android.text.TextPaint; -import android.text.TextUtils; -import android.text.style.BackgroundColorSpan; -import android.text.style.CharacterStyle; -import android.text.style.ForegroundColorSpan; -import android.text.style.StyleSpan; -import android.text.style.UnderlineSpan; -import android.util.AttributeSet; -import android.util.DisplayMetrics; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.PopupWindow; -import android.widget.TextView; - -import com.android.inputmethod.compat.FrameLayoutCompatUtils; -import com.android.inputmethod.compat.LinearLayoutCompatUtils; -import com.android.inputmethod.keyboard.KeyboardActionListener; -import com.android.inputmethod.keyboard.MoreKeysPanel; -import com.android.inputmethod.keyboard.PointerTracker; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; - -import java.util.ArrayList; -import java.util.List; - -public class CandidateView extends LinearLayout implements OnClickListener, OnLongClickListener { - public interface Listener { - public boolean addWordToDictionary(String word); - public void pickSuggestionManually(int index, CharSequence word); - } - - // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. - public static final int MAX_SUGGESTIONS = 18; - - private static final boolean DBG = LatinImeLogger.sDBG; - - private final ViewGroup mCandidatesPlacer; - private final ViewGroup mCandidatesStrip; - private View mKeyboardView; - - private final View mMoreSuggestionsContainer; - private final MoreSuggestionsView mMoreSuggestionsView; - private final MoreSuggestions.Builder mMoreSuggestionsBuilder; - private final PopupWindow mMoreSuggestionsWindow; - - private final ArrayList mWords = new ArrayList(); - private final ArrayList mInfos = new ArrayList(); - private final ArrayList mDividers = new ArrayList(); - - private final PopupWindow mPreviewPopup; - private final TextView mPreviewText; - - private Listener mListener; - private SuggestedWords mSuggestions = SuggestedWords.EMPTY; - private boolean mShowingAutoCorrectionInverted; - - private final SuggestionsStripParams mStripParams; - private static final float MIN_TEXT_XSCALE = 0.70f; - - private final UiHandler mHandler = new UiHandler(this); - - private static class UiHandler extends StaticInnerHandlerWrapper { - private static final int MSG_HIDE_PREVIEW = 0; - private static final int MSG_UPDATE_SUGGESTION = 1; - - private static final long DELAY_HIDE_PREVIEW = 1300; - private static final long DELAY_UPDATE_SUGGESTION = 300; - - public UiHandler(CandidateView outerInstance) { - super(outerInstance); - } - - @Override - public void dispatchMessage(Message msg) { - final CandidateView candidateView = getOuterInstance(); - switch (msg.what) { - case MSG_HIDE_PREVIEW: - candidateView.hidePreview(); - break; - case MSG_UPDATE_SUGGESTION: - candidateView.updateSuggestions(); - break; - } - } - - public void postHidePreview() { - cancelHidePreview(); - sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); - } - - public void cancelHidePreview() { - removeMessages(MSG_HIDE_PREVIEW); - } - - public void postUpdateSuggestions() { - cancelUpdateSuggestions(); - sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), - DELAY_UPDATE_SUGGESTION); - } - - public void cancelUpdateSuggestions() { - removeMessages(MSG_UPDATE_SUGGESTION); - } - - public void cancelAllMessages() { - cancelHidePreview(); - cancelUpdateSuggestions(); - } - } - - private static class CandidateViewParams { - public final int mPadding; - public final int mDividerWidth; - public final int mCandidateStripHeight; - - protected final List mWords; - protected final List mDividers; - protected final List mInfos; - - protected CandidateViewParams(List words, List dividers, - List infos) { - mWords = words; - mDividers = dividers; - mInfos = infos; - - final TextView word = words.get(0); - final View divider = dividers.get(0); - mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); - divider.measure( - ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); - mDividerWidth = divider.getMeasuredWidth(); - - final Resources res = word.getResources(); - mCandidateStripHeight = res.getDimensionPixelSize(R.dimen.candidate_strip_height); - } - } - - private static class SuggestionsStripParams extends CandidateViewParams { - private static final int DEFAULT_CANDIDATE_COUNT_IN_STRIP = 3; - private static final int DEFAULT_CENTER_CANDIDATE_PERCENTILE = 40; - private static final int PUNCTUATIONS_IN_STRIP = 6; - - private final int mColorTypedWord; - private final int mColorAutoCorrect; - private final int mColorSuggestedCandidate; - public final int mCandidateCountInStrip; - private final float mCenterCandidateWeight; - private final int mCenterCandidateIndex; - private final Drawable mMoreCandidateHint; - - private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); - private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); - private final CharacterStyle mInvertedForegroundColorSpan; - private final CharacterStyle mInvertedBackgroundColorSpan; - private static final int AUTO_CORRECT_BOLD = 0x01; - private static final int AUTO_CORRECT_UNDERLINE = 0x02; - private static final int AUTO_CORRECT_INVERT = 0x04; - private static final int VALID_TYPED_WORD_BOLD = 0x08; - - private final int mSuggestionStripOption; - - private final ArrayList mTexts = new ArrayList(); - - public boolean mMoreSuggestionsAvailable; - - public final TextView mWordToSaveView; - private final TextView mHintToSaveView; - private final CharSequence mHintToSaveText; - - public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, - List words, List dividers, List infos) { - super(words, dividers, infos); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.CandidateView, defStyle, R.style.CandidateViewStyle); - mSuggestionStripOption = a.getInt(R.styleable.CandidateView_suggestionStripOption, 0); - mColorTypedWord = a.getColor(R.styleable.CandidateView_colorTypedWord, 0); - mColorAutoCorrect = a.getColor(R.styleable.CandidateView_colorAutoCorrect, 0); - mColorSuggestedCandidate = a.getColor(R.styleable.CandidateView_colorSuggested, 0); - mCandidateCountInStrip = a.getInt( - R.styleable.CandidateView_candidateCountInStrip, - DEFAULT_CANDIDATE_COUNT_IN_STRIP); - mCenterCandidateWeight = a.getInt( - R.styleable.CandidateView_centerCandidatePercentile, - DEFAULT_CENTER_CANDIDATE_PERCENTILE) / 100.0f; - a.recycle(); - - mCenterCandidateIndex = mCandidateCountInStrip / 2; - final Resources res = context.getResources(); - mMoreCandidateHint = res.getDrawable(R.drawable.more_suggestions_hint); - - mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); - mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); - - final LayoutInflater inflater = LayoutInflater.from(context); - mWordToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null); - mHintToSaveView = (TextView)inflater.inflate(R.layout.candidate_word, null); - mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); - } - - private CharSequence getStyledCandidateWord(SuggestedWords suggestions, int pos) { - final CharSequence word = suggestions.getWord(pos); - final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); - final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; - if (!isAutoCorrect && !isTypedWordValid) - return word; - - final int len = word.length(); - final Spannable spannedWord = new SpannableString(word); - final int option = mSuggestionStripOption; - if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) - || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { - spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { - spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - } - return spannedWord; - } - - private static boolean willAutoCorrect(SuggestedWords suggestions) { - return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; - } - - private int getWordPosition(int index, SuggestedWords suggestions) { - // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more - // suggestions. - final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; - if (index == mCenterCandidateIndex) { - return centerPos; - } else if (index == centerPos) { - return mCenterCandidateIndex; - } else { - return index; - } - } - - private int getCandidateTextColor(int index, SuggestedWords suggestions, int pos) { - // TODO: Need to revisit this logic with bigram suggestions - final boolean isSuggestedCandidate = (pos != 0); - - final int color; - if (index == mCenterCandidateIndex && willAutoCorrect(suggestions)) { - color = mColorAutoCorrect; - } else if (isSuggestedCandidate) { - color = mColorSuggestedCandidate; - } else { - color = mColorTypedWord; - } - - final SuggestedWordInfo info = (pos < suggestions.size()) - ? suggestions.getInfo(pos) : null; - if (info != null && info.isObsoleteSuggestedWord()) { - return applyAlpha(color, 0.5f); - } else { - return color; - } - } - - private static int applyAlpha(final int color, final float alpha) { - final int newAlpha = (int)(Color.alpha(color) * alpha); - return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); - } - - public CharSequence getInvertedText(CharSequence text) { - if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0) - return null; - final int len = text.length(); - final Spannable word = new SpannableString(text); - word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); - return word; - } - - public void layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup placer, - int stripWidth) { - if (suggestions.isPunctuationSuggestions()) { - layoutPunctuationSuggestions(suggestions, stripView); - return; - } - - final int countInStrip = mCandidateCountInStrip; - setupTexts(suggestions, countInStrip); - mMoreSuggestionsAvailable = (suggestions.size() > countInStrip); - int x = 0; - for (int index = 0; index < countInStrip; index++) { - final int pos = getWordPosition(index, suggestions); - - if (index != 0) { - final View divider = mDividers.get(pos); - // Add divider if this isn't the left most suggestion in candidate strip. - stripView.addView(divider); - x += divider.getMeasuredWidth(); - } - - final CharSequence styled = mTexts.get(pos); - final TextView word = mWords.get(pos); - if (index == mCenterCandidateIndex && mMoreSuggestionsAvailable) { - // TODO: This "more suggestions hint" should have nicely designed icon. - word.setCompoundDrawablesWithIntrinsicBounds( - null, null, null, mMoreCandidateHint); - // HACK: To align with other TextView that has no compound drawables. - word.setCompoundDrawablePadding(-mMoreCandidateHint.getIntrinsicHeight()); - } else { - word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); - } - - // Disable this candidate if the suggestion is null or empty. - word.setEnabled(!TextUtils.isEmpty(styled)); - word.setTextColor(getCandidateTextColor(index, suggestions, pos)); - final int width = getCandidateWidth(index, stripWidth); - final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); - final float scaleX = word.getTextScaleX(); - word.setText(text); // TextView.setText() resets text scale x to 1.0. - word.setTextScaleX(scaleX); - stripView.addView(word); - setLayoutWeight( - word, getCandidateWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); - x += word.getMeasuredWidth(); - - if (DBG) { - final CharSequence debugInfo = getDebugInfo(suggestions, pos); - if (debugInfo != null) { - final TextView info = mInfos.get(pos); - info.setText(debugInfo); - placer.addView(info); - info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - final int infoWidth = info.getMeasuredWidth(); - final int y = info.getMeasuredHeight(); - FrameLayoutCompatUtils.placeViewAt( - info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); - } - } - } - } - - private int getCandidateWidth(int index, int maxWidth) { - final int paddings = mPadding * mCandidateCountInStrip; - final int dividers = mDividerWidth * (mCandidateCountInStrip - 1); - final int availableWidth = maxWidth - paddings - dividers; - return (int)(availableWidth * getCandidateWeight(index)); - } - - private float getCandidateWeight(int index) { - if (index == mCenterCandidateIndex) { - return mCenterCandidateWeight; - } else { - // TODO: Revisit this for cases of 5 or more suggestions - return (1.0f - mCenterCandidateWeight) / (mCandidateCountInStrip - 1); - } - } - - private void setupTexts(SuggestedWords suggestions, int countInStrip) { - mTexts.clear(); - final int count = Math.min(suggestions.size(), countInStrip); - for (int pos = 0; pos < count; pos++) { - final CharSequence styled = getStyledCandidateWord(suggestions, pos); - mTexts.add(styled); - } - for (int pos = count; pos < countInStrip; pos++) { - // Make this inactive for touches in layout(). - mTexts.add(null); - } - } - - private void layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) { - final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP); - for (int index = 0; index < countInStrip; index++) { - if (index != 0) { - // Add divider if this isn't the left most suggestion in candidate strip. - stripView.addView(mDividers.get(index)); - } - - final TextView word = mWords.get(index); - word.setEnabled(true); - word.setTextColor(mColorTypedWord); - final CharSequence text = suggestions.getWord(index); - word.setText(text); - word.setTextScaleX(1.0f); - word.setCompoundDrawables(null, null, null, null); - stripView.addView(word); - setLayoutWeight(word, 1.0f, mCandidateStripHeight); - } - mMoreSuggestionsAvailable = false; - } - - public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, - int stripWidth) { - final int width = stripWidth - mDividerWidth - mPadding * 2; - - final TextView wordView = mWordToSaveView; - wordView.setTextColor(mColorTypedWord); - final int wordWidth = (int)(width * mCenterCandidateWeight); - final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); - final float wordScaleX = wordView.getTextScaleX(); - wordView.setTag(word); - wordView.setText(text); - wordView.setTextScaleX(wordScaleX); - stripView.addView(wordView); - setLayoutWeight(wordView, mCenterCandidateWeight, ViewGroup.LayoutParams.MATCH_PARENT); - - stripView.addView(mDividers.get(0)); - - final TextView hintView = mHintToSaveView; - hintView.setTextColor(mColorAutoCorrect); - final int hintWidth = width - wordWidth; - final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint()); - hintView.setText(mHintToSaveText); - hintView.setTextScaleX(hintScaleX); - stripView.addView(hintView); - setLayoutWeight( - hintView, 1.0f - mCenterCandidateWeight, ViewGroup.LayoutParams.MATCH_PARENT); - } - } - - /** - * Construct a CandidateView for showing suggested words for completion. - * @param context - * @param attrs - */ - public CandidateView(Context context, AttributeSet attrs) { - this(context, attrs, R.attr.candidateViewStyle); - } - - public CandidateView(Context context, AttributeSet attrs, int defStyle) { - // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument - // constructor. - // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon - // backward compatibility with the version 10 or earlier of the API. - super(context, attrs); - if (defStyle != R.attr.candidateViewStyle) { - throw new IllegalArgumentException( - "can't accept defStyle other than R.attr.candidateViewStyle: defStyle=" - + defStyle); - } - setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( - context, attrs, defStyle, R.style.CandidateViewStyle)); - - final LayoutInflater inflater = LayoutInflater.from(context); - inflater.inflate(R.layout.candidates_strip, this); - - mPreviewPopup = new PopupWindow(context); - mPreviewText = (TextView) inflater.inflate(R.layout.candidate_preview, null); - mPreviewPopup.setWindowLayoutMode( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mPreviewPopup.setContentView(mPreviewText); - mPreviewPopup.setBackgroundDrawable(null); - - mCandidatesPlacer = (ViewGroup)findViewById(R.id.candidates_placer); - mCandidatesStrip = (ViewGroup)findViewById(R.id.candidates_strip); - for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { - final TextView word = (TextView)inflater.inflate(R.layout.candidate_word, null); - word.setTag(pos); - word.setOnClickListener(this); - word.setOnLongClickListener(this); - mWords.add(word); - final View divider = inflater.inflate(R.layout.candidate_divider, null); - divider.setTag(pos); - divider.setOnClickListener(this); - mDividers.add(divider); - mInfos.add((TextView)inflater.inflate(R.layout.candidate_info, null)); - } - - mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers, - mInfos); - mStripParams.mWordToSaveView.setOnClickListener(this); - - mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); - mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer - .findViewById(R.id.more_suggestions_view); - mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); - mMoreSuggestionsWindow = new PopupWindow(context); - mMoreSuggestionsWindow.setWindowLayoutMode( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - mMoreSuggestionsWindow.setBackgroundDrawable(null); - } - - /** - * A connection back to the input method. - * @param listener - */ - public void setListener(Listener listener, View inputView) { - mListener = listener; - mKeyboardView = inputView.findViewById(R.id.keyboard_view); - } - - public void setSuggestions(SuggestedWords suggestions) { - if (suggestions == null) - return; - mSuggestions = suggestions; - if (mShowingAutoCorrectionInverted) { - mHandler.postUpdateSuggestions(); - } else { - updateSuggestions(); - } - } - - private void updateSuggestions() { - clear(); - if (mSuggestions.size() == 0) - return; - - mStripParams.layout(mSuggestions, mCandidatesStrip, mCandidatesPlacer, getWidth()); - } - - private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { - if (DBG && pos < suggestions.size()) { - final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); - if (wordInfo != null) { - final CharSequence debugInfo = wordInfo.getDebugString(); - if (!TextUtils.isEmpty(debugInfo)) { - return debugInfo; - } - } - } - return null; - } - - private static void setLayoutWeight(View v, float weight, int height) { - final ViewGroup.LayoutParams lp = v.getLayoutParams(); - if (lp instanceof LinearLayout.LayoutParams) { - final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; - llp.weight = weight; - llp.width = 0; - llp.height = height; - } - } - - private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { - paint.setTextScaleX(1.0f); - final int width = getTextWidth(text, paint); - if (width <= maxWidth) { - return 1.0f; - } - return maxWidth / (float)width; - } - - private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, - TextPaint paint) { - if (text == null) return null; - paint.setTextScaleX(1.0f); - final int width = getTextWidth(text, paint); - if (width <= maxWidth) { - return text; - } - final float scaleX = maxWidth / (float)width; - if (scaleX >= MIN_TEXT_XSCALE) { - paint.setTextScaleX(scaleX); - return text; - } - - // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get - // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). - final CharSequence ellipsized = TextUtils.ellipsize( - text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); - paint.setTextScaleX(MIN_TEXT_XSCALE); - return ellipsized; - } - - private static int getTextWidth(CharSequence text, TextPaint paint) { - if (TextUtils.isEmpty(text)) return 0; - final Typeface savedTypeface = paint.getTypeface(); - paint.setTypeface(getTextTypeface(text)); - final int len = text.length(); - final float[] widths = new float[len]; - final int count = paint.getTextWidths(text, 0, len, widths); - int width = 0; - for (int i = 0; i < count; i++) { - width += Math.round(widths[i] + 0.5f); - } - paint.setTypeface(savedTypeface); - return width; - } - - private static Typeface getTextTypeface(CharSequence text) { - if (!(text instanceof SpannableString)) - return Typeface.DEFAULT; - - final SpannableString ss = (SpannableString)text; - final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); - if (styles.length == 0) - return Typeface.DEFAULT; - - switch (styles[0].getStyle()) { - case Typeface.BOLD: return Typeface.DEFAULT_BOLD; - // TODO: BOLD_ITALIC, ITALIC case? - default: return Typeface.DEFAULT; - } - } - - public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { - final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord); - if (inverted == null) - return; - final TextView tv = mWords.get(1); - tv.setText(inverted); - mShowingAutoCorrectionInverted = true; - } - - public boolean isShowingAddToDictionaryHint() { - return mCandidatesStrip.getChildCount() > 0 - && mCandidatesStrip.getChildAt(0) == mStripParams.mWordToSaveView; - } - - public void showAddToDictionaryHint(CharSequence word) { - clear(); - mStripParams.layoutAddToDictionaryHint(word, mCandidatesStrip, getWidth()); - } - - public boolean dismissAddToDictionaryHint() { - if (isShowingAddToDictionaryHint()) { - clear(); - return true; - } - return false; - } - - public SuggestedWords getSuggestions() { - return mSuggestions; - } - - public void clear() { - mShowingAutoCorrectionInverted = false; - mCandidatesPlacer.removeAllViews(); - mCandidatesPlacer.addView(mCandidatesStrip); - mCandidatesStrip.removeAllViews(); - mMoreSuggestionsWindow.dismiss(); - } - - private void hidePreview() { - mPreviewPopup.dismiss(); - } - - private void showPreview(View view, CharSequence word) { - if (TextUtils.isEmpty(word)) - return; - - final TextView previewText = mPreviewText; - previewText.setTextColor(mStripParams.mColorTypedWord); - previewText.setText(word); - previewText.measure( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - final int[] offsetInWindow = new int[2]; - view.getLocationInWindow(offsetInWindow); - final int posX = offsetInWindow[0]; - final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); - final PopupWindow previewPopup = mPreviewPopup; - if (previewPopup.isShowing()) { - previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); - } else { - previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); - } - previewText.setVisibility(VISIBLE); - mHandler.postHidePreview(); - } - - private void addToDictionary(CharSequence word) { - if (mListener.addWordToDictionary(word.toString())) { - final CharSequence message = getContext().getString(R.string.added_word, word); - showPreview(mStripParams.mWordToSaveView, message); - } - } - - private final KeyboardActionListener mMoreSuggestionsListener = - new KeyboardActionListener.Adapter() { - @Override - public boolean onCustomRequest(int requestCode) { - final int index = requestCode; - final CharSequence word = mSuggestions.getWord(index); - mListener.pickSuggestionManually(index, word); - mMoreSuggestionsView.dismissMoreKeysPanel(); - return true; - } - - @Override - public void onCancelInput() { - mMoreSuggestionsView.dismissMoreKeysPanel(); - } - }; - - private final MoreKeysPanel.Controller mMoreSuggestionsController = - new MoreKeysPanel.Controller() { - @Override - public boolean dismissMoreKeysPanel() { - if (mMoreSuggestionsWindow.isShowing()) { - mMoreSuggestionsWindow.dismiss(); - return true; - } - return false; - } - }; - - @Override - public boolean onLongClick(View view) { - final SuggestionsStripParams params = mStripParams; - if (params.mMoreSuggestionsAvailable) { - final int stripWidth = getWidth(); - final View container = mMoreSuggestionsContainer; - final int maxWidth = stripWidth - container.getPaddingLeft() - - container.getPaddingRight(); - final DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); - // TODO: Revise how we determine the height - final int maxHeight = dm.heightPixels - mKeyboardView.getHeight() - getHeight() * 3; - final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; - builder.layout(mSuggestions, params.mCandidateCountInStrip, maxWidth, maxHeight); - mMoreSuggestionsView.setKeyboard(builder.build()); - container.measure( - ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); - - final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; - final int pointX = stripWidth / 2; - final int pointY = 0; - moreKeysPanel.showMoreKeysPanel( - this, mMoreSuggestionsController, pointX, pointY, - mMoreSuggestionsWindow, mMoreSuggestionsListener); - // TODO: Should figure out how to select the pointer tracker correctly. - final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel); - final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); - final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); - tracker.onShowMoreKeysPanel( - translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); - view.setPressed(false); - // TODO: Should gray out the keyboard here as well? - return true; - } - return false; - } - - @Override - public boolean dispatchTouchEvent(MotionEvent me) { - if (!mMoreSuggestionsWindow.isShowing()) { - return super.dispatchTouchEvent(me); - } - final int action = me.getAction(); - final long eventTime = me.getEventTime(); - final int index = me.getActionIndex(); - final int id = me.getPointerId(index); - final PointerTracker tracker = PointerTracker.getPointerTracker(id, mMoreSuggestionsView); - final int x = mMoreSuggestionsView.translateX((int)me.getX(index)); - final int y = mMoreSuggestionsView.translateY((int)me.getY(index)); - switch (action) { - case MotionEvent.ACTION_DOWN: - case MotionEvent.ACTION_POINTER_DOWN: - tracker.onDownEvent(x, y, eventTime, mMoreSuggestionsView); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_POINTER_UP: - tracker.onUpEvent(x, y, eventTime); - break; - case MotionEvent.ACTION_MOVE: - tracker.onMoveEvent(x, y, eventTime); - break; - case MotionEvent.ACTION_CANCEL: - tracker.onCancelEvent(x, y, eventTime); - break; - } - return true; - } - - @Override - public void onClick(View view) { - if (view == mStripParams.mWordToSaveView) { - addToDictionary((CharSequence)view.getTag()); - clear(); - return; - } - - final Object tag = view.getTag(); - if (!(tag instanceof Integer)) - return; - final int index = (Integer) tag; - if (index >= mSuggestions.size()) - return; - - final CharSequence word = mSuggestions.getWord(index); - mListener.pickSuggestionManually(index, word); - } - - @Override - public void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mHandler.cancelAllMessages(); - hidePreview(); - } -} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index da6c22107..85363fd36 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -77,7 +77,7 @@ import java.util.Locale; * Input method implementation for Qwerty'ish keyboard. */ public class LatinIME extends InputMethodServiceCompatWrapper implements KeyboardActionListener, - CandidateView.Listener { + SuggestionsView.Listener { private static final String TAG = LatinIME.class.getSimpleName(); private static final boolean PERF_DEBUG = false; private static final boolean TRACE = false; @@ -157,9 +157,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private Settings.Values mSettingsValues; - private View mCandidateViewContainer; - private int mCandidateStripHeight; - private CandidateView mCandidateView; + private View mSuggestionsContainer; + private int mSuggestionsStripHeight; + private SuggestionsView mSuggestionsView; private Suggest mSuggest; private CompletionInfo[] mApplicationSpecifiedCompletions; @@ -254,7 +254,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar break; case MSG_UPDATE_OLD_SUGGESTIONS: latinIme.mRecorrection.fetchAndDisplayRecorrectionSuggestions( - latinIme.mVoiceProxy, latinIme.mCandidateView, + latinIme.mVoiceProxy, latinIme.mSuggestionsView, latinIme.mSuggest, latinIme.mKeyboardSwitcher, latinIme.mWordComposer, latinIme.mHasUncommittedTypedChars, latinIme.mLastSelectionStart, latinIme.mLastSelectionEnd, latinIme.mSettingsValues.mWordSeparators); @@ -607,11 +607,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void setInputView(View view) { super.setInputView(view); - mCandidateViewContainer = view.findViewById(R.id.candidates_container); - mCandidateView = (CandidateView) view.findViewById(R.id.candidates); - if (mCandidateView != null) - mCandidateView.setListener(this, view); - mCandidateStripHeight = (int)mResources.getDimension(R.dimen.candidate_strip_height); + mSuggestionsContainer = view.findViewById(R.id.suggestions_container); + mSuggestionsView = (SuggestionsView) view.findViewById(R.id.suggestions_view); + if (mSuggestionsView != null) + mSuggestionsView.setListener(this, view); + mSuggestionsStripHeight = (int)mResources.getDimension(R.dimen.suggestions_strip_height); } @Override @@ -678,9 +678,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switcher.loadKeyboard(attribute, mSettingsValues); } - if (mCandidateView != null) - mCandidateView.clear(); - setSuggestionStripShownInternal(isCandidateStripVisible(), /* needsInputViewShown */ false); + if (mSuggestionsView != null) + mSuggestionsView.clear(); + setSuggestionStripShownInternal( + isSuggestionsStripVisible(), /* needsInputViewShown */ false); // Delay updating suggestions because keyboard input view may not be shown at this point. mHandler.postUpdateSuggestions(); @@ -708,7 +709,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) { mIsSettingsSuggestionStripOn = true; - // Make sure that passwords are not displayed in candidate view + // Make sure that passwords are not displayed in {@link SuggestionsView}. if (InputTypeCompatUtils.isPasswordInputType(inputType) || InputTypeCompatUtils.isVisiblePasswordInputType(inputType)) { mIsSettingsSuggestionStripOn = false; @@ -819,7 +820,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && (selectionChanged || candidatesCleared)) { if (candidatesCleared) { // If the composing span has been cleared, save the typed word in the history for - // recorrection before we reset the candidate strip. Then, we'll be able to show + // recorrection before we reset the suggestions strip. Then, we'll be able to show // suggestions for recorrection right away. mRecorrection.saveRecorrectionSuggestion(mWordComposer, mComposingStringBuilder); } @@ -853,7 +854,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mLastSelectionEnd = newSelEnd; mRecorrection.updateRecorrectionSelection(mKeyboardSwitcher, - mCandidateView, candidatesStart, candidatesEnd, newSelStart, + mSuggestionsView, candidatesStart, candidatesEnd, newSelStart, newSelEnd, oldSelStart, mLastSelectionStart, mLastSelectionEnd, mHasUncommittedTypedChars); } @@ -866,10 +867,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides - * the candidates view when this happens, but only if the extracted text + * the suggestions view when this happens, but only if the extracted text * editor has a vertical scroll bar because its text doesn't fit. * Here we override the behavior due to the possibility that a re-correction could - * cause the candidate strip to disappear and re-appear. + * cause the suggestions strip to disappear and re-appear. */ @Override public void onExtractedTextClicked() { @@ -881,11 +882,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /** * This is called when the user has performed a cursor movement in the * extracted text view, when it is running in fullscreen mode. The default - * implementation hides the candidates view when a vertical movement + * implementation hides the suggestions view when a vertical movement * happens, but only if the extracted text editor has a vertical scroll bar * because its text doesn't fit. * Here we override the behavior due to the possibility that a re-correction could - * cause the candidate strip to disappear and re-appear. + * cause the suggestions strip to disappear and re-appear. */ @Override public void onExtractedCursorMovement(int dx, int dy) { @@ -938,20 +939,20 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void setSuggestionStripShownInternal(boolean shown, boolean needsInputViewShown) { - // TODO: Modify this if we support candidates with hard keyboard - if (onEvaluateInputViewShown() && mCandidateViewContainer != null) { - final boolean shouldShowCandidates = shown + // TODO: Modify this if we support suggestions with hard keyboard + if (onEvaluateInputViewShown() && mSuggestionsContainer != null) { + final boolean shouldShowSuggestions = shown && (needsInputViewShown ? mKeyboardSwitcher.isInputViewShown() : true); if (isFullscreenMode()) { // No need to have extra space to show the key preview. - mCandidateViewContainer.setMinimumHeight(0); - mCandidateViewContainer.setVisibility( - shouldShowCandidates ? View.VISIBLE : View.GONE); + mSuggestionsContainer.setMinimumHeight(0); + mSuggestionsContainer.setVisibility( + shouldShowSuggestions ? View.VISIBLE : View.GONE); } else { // We must control the visibility of the suggestion strip in order to avoid clipped // key previews, even when we don't show the suggestion strip. - mCandidateViewContainer.setVisibility( - shouldShowCandidates ? View.VISIBLE : View.INVISIBLE); + mSuggestionsContainer.setVisibility( + shouldShowSuggestions ? View.VISIBLE : View.INVISIBLE); } } } @@ -964,14 +965,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void onComputeInsets(InputMethodService.Insets outInsets) { super.onComputeInsets(outInsets); final KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); - if (inputView == null || mCandidateViewContainer == null) + if (inputView == null || mSuggestionsContainer == null) return; - final int containerHeight = mCandidateViewContainer.getHeight(); + final int containerHeight = mSuggestionsContainer.getHeight(); int touchY = containerHeight; // Need to set touchable region only if input view is being shown if (mKeyboardSwitcher.isInputViewShown()) { - if (mCandidateViewContainer.getVisibility() == View.VISIBLE) { - touchY -= mCandidateStripHeight; + if (mSuggestionsContainer.getVisibility() == View.VISIBLE) { + touchY -= mSuggestionsStripHeight; } final int touchWidth = inputView.getWidth(); final int touchHeight = inputView.getHeight() + containerHeight @@ -1321,7 +1322,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (mEnteredText != null && sameAsTextBeforeCursor(ic, mEnteredText)) { ic.deleteSurroundingText(mEnteredText.length(), 0); } else if (deleteChar) { - if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) { + if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { // Go back to the suggestion mode if the user canceled the // "Touch again to save". // NOTE: In gerenal, we don't revert the word when backspacing @@ -1440,7 +1441,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mVoiceProxy.handleSeparator(); // Should dismiss the "Touch again to save" message when handling separator - if (mCandidateView != null && mCandidateView.dismissAddToDictionaryHint()) { + if (mSuggestionsView != null && mSuggestionsView.dismissAddToDictionaryHint()) { mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); } @@ -1491,8 +1492,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (!TextUtils.isEmpty(typedWord) && !typedWord.equals(mBestWord)) { InputConnectionCompatUtils.commitCorrection( ic, mLastSelectionEnd - typedWord.length(), typedWord, mBestWord); - if (mCandidateView != null) - mCandidateView.onAutoCorrectionInverted(mBestWord); + if (mSuggestionsView != null) + mSuggestionsView.onAutoCorrectionInverted(mBestWord); } } if (Keyboard.CODE_SPACE == primaryCode) { @@ -1527,7 +1528,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public boolean isShowingPunctuationList() { - return mSettingsValues.mSuggestPuncList == mCandidateView.getSuggestions(); + return mSettingsValues.mSuggestPuncList == mSuggestionsView.getSuggestions(); } public boolean isShowingSuggestionsStrip() { @@ -1536,10 +1537,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT); } - public boolean isCandidateStripVisible() { - if (mCandidateView == null) + public boolean isSuggestionsStripVisible() { + if (mSuggestionsView == null) return false; - if (mCandidateView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting()) + if (mSuggestionsView.isShowingAddToDictionaryHint() || TextEntryState.isRecorrecting()) return true; if (!isShowingSuggestionsStrip()) return false; @@ -1561,7 +1562,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } setInputView(v); } - setSuggestionStripShown(isCandidateStripVisible()); + setSuggestionStripShown(isSuggestionsStripVisible()); updateInputViewShown(); mHandler.postUpdateSuggestions(); } @@ -1571,8 +1572,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void setSuggestions(SuggestedWords words) { - if (mCandidateView != null) { - mCandidateView.setSuggestions(words); + if (mSuggestionsView != null) { + mSuggestionsView.setSuggestions(words); mKeyboardSwitcher.onAutoCorrectionStateChanged( words.hasWordAboveAutoCorrectionScoreThreshold()); } @@ -1625,11 +1626,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // length == 1). if (typedWord != null) { if (builder.size() > 1 || typedWord.length() == 1 || typedWordValid - || mCandidateView.isShowingAddToDictionaryHint()) { + || mSuggestionsView.isShowingAddToDictionaryHint()) { builder.setTypedWordValid(typedWordValid).setHasMinimalSuggestion( autoCorrectionAvailable); } else { - final SuggestedWords previousSuggestions = mCandidateView.getSuggestions(); + final SuggestedWords previousSuggestions = mSuggestionsView.getSuggestions(); if (previousSuggestions == mSettingsValues.mSuggestPuncList) return; builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); @@ -1651,11 +1652,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } else { mBestWord = null; } - setSuggestionStripShown(isCandidateStripVisible()); + setSuggestionStripShown(isSuggestionsStripVisible()); } private boolean pickDefaultSuggestion(int separatorCode) { - // Complete any pending candidate query first + // Complete any pending suggestions query first if (mHandler.hasPendingUpdateSuggestions()) { mHandler.cancelUpdateSuggestions(); updateSuggestions(); @@ -1674,7 +1675,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar @Override public void pickSuggestionManually(int index, CharSequence suggestion) { - SuggestedWords suggestions = mCandidateView.getSuggestions(); + SuggestedWords suggestions = mSuggestionsView.getSuggestions(); mVoiceProxy.flushAndLogAllTextModificationCounters(index, suggestion, mSettingsValues.mWordSeparators); @@ -1690,8 +1691,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitCompletion(completionInfo); } mCommittedLength = suggestion.length(); - if (mCandidateView != null) { - mCandidateView.clear(); + if (mSuggestionsView != null) { + mSuggestionsView.clear(); } mKeyboardSwitcher.updateShiftState(); if (ic != null) { @@ -1786,7 +1787,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } if (showingAddToDictionaryHint) { if (mIsUserDictionaryAvaliable) { - mCandidateView.showAddToDictionaryHint(suggestion); + mSuggestionsView.showAddToDictionaryHint(suggestion); } else { mHandler.postUpdateSuggestions(); } @@ -1806,7 +1807,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final InputConnection ic = getCurrentInputConnection(); if (ic != null) { mVoiceProxy.rememberReplacedWord(bestWord, mSettingsValues.mWordSeparators); - SuggestedWords suggestedWords = mCandidateView.getSuggestions(); + SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); ic.commitText(SuggestionSpanUtils.getTextWithSuggestionSpan( this, bestWord, suggestedWords), 1); } @@ -1842,7 +1843,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar public void setPunctuationSuggestions() { setSuggestions(mSettingsValues.mSuggestPuncList); - setSuggestionStripShown(isCandidateStripVisible()); + setSuggestionStripShown(isSuggestionsStripVisible()); } private void addToUserUnigramAndBigramDictionaries(CharSequence suggestion, diff --git a/java/src/com/android/inputmethod/latin/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/MoreSuggestions.java index 0446fb2a8..a9e75b7b3 100644 --- a/java/src/com/android/inputmethod/latin/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/MoreSuggestions.java @@ -43,10 +43,10 @@ public class MoreSuggestions extends Keyboard { private int mToPos; public static class MoreSuggestionsParam extends KeyboardParams { - private final int[] mWidths = new int[CandidateView.MAX_SUGGESTIONS]; - private final int[] mRowNumbers = new int[CandidateView.MAX_SUGGESTIONS]; - private final int[] mColumnOrders = new int[CandidateView.MAX_SUGGESTIONS]; - private final int[] mNumColumnsInRow = new int[CandidateView.MAX_SUGGESTIONS]; + private final int[] mWidths = new int[SuggestionsView.MAX_SUGGESTIONS]; + private final int[] mRowNumbers = new int[SuggestionsView.MAX_SUGGESTIONS]; + private final int[] mColumnOrders = new int[SuggestionsView.MAX_SUGGESTIONS]; + private final int[] mNumColumnsInRow = new int[SuggestionsView.MAX_SUGGESTIONS]; private static final int MAX_COLUMNS_IN_ROW = 3; private int mNumRows; @@ -60,7 +60,7 @@ public class MoreSuggestions extends Keyboard { int row = 0; int pos = fromPos, rowStartPos = fromPos; - final int size = Math.min(suggestions.size(), CandidateView.MAX_SUGGESTIONS); + final int size = Math.min(suggestions.size(), SuggestionsView.MAX_SUGGESTIONS); while (pos < size) { final CharSequence word = suggestions.getWord(pos); // TODO: Should take care of text x-scaling. diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java new file mode 100644 index 000000000..617d7f1f2 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java @@ -0,0 +1,819 @@ +/* + * Copyright (C) 2011 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.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Message; +import android.os.SystemClock; +import android.text.Spannable; +import android.text.SpannableString; +import android.text.Spanned; +import android.text.TextPaint; +import android.text.TextUtils; +import android.text.style.BackgroundColorSpan; +import android.text.style.CharacterStyle; +import android.text.style.ForegroundColorSpan; +import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; +import android.util.AttributeSet; +import android.util.DisplayMetrics; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; +import android.view.ViewGroup; +import android.widget.LinearLayout; +import android.widget.PopupWindow; +import android.widget.TextView; + +import com.android.inputmethod.compat.FrameLayoutCompatUtils; +import com.android.inputmethod.compat.LinearLayoutCompatUtils; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.MoreKeysPanel; +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + +import java.util.ArrayList; +import java.util.List; + +public class SuggestionsView extends LinearLayout implements OnClickListener, OnLongClickListener { + public interface Listener { + public boolean addWordToDictionary(String word); + public void pickSuggestionManually(int index, CharSequence word); + } + + // The maximum number of suggestions available. See {@link Suggest#mPrefMaxSuggestions}. + public static final int MAX_SUGGESTIONS = 18; + + private static final boolean DBG = LatinImeLogger.sDBG; + + private final ViewGroup mSuggestionsPlacer; + private final ViewGroup mSuggestionsStrip; + private View mKeyboardView; + + private final View mMoreSuggestionsContainer; + private final MoreSuggestionsView mMoreSuggestionsView; + private final MoreSuggestions.Builder mMoreSuggestionsBuilder; + private final PopupWindow mMoreSuggestionsWindow; + + private final ArrayList mWords = new ArrayList(); + private final ArrayList mInfos = new ArrayList(); + private final ArrayList mDividers = new ArrayList(); + + private final PopupWindow mPreviewPopup; + private final TextView mPreviewText; + + private Listener mListener; + private SuggestedWords mSuggestions = SuggestedWords.EMPTY; + private boolean mShowingAutoCorrectionInverted; + + private final SuggestionsStripParams mStripParams; + private static final float MIN_TEXT_XSCALE = 0.70f; + + private final UiHandler mHandler = new UiHandler(this); + + private static class UiHandler extends StaticInnerHandlerWrapper { + private static final int MSG_HIDE_PREVIEW = 0; + private static final int MSG_UPDATE_SUGGESTION = 1; + + private static final long DELAY_HIDE_PREVIEW = 1300; + private static final long DELAY_UPDATE_SUGGESTION = 300; + + public UiHandler(SuggestionsView outerInstance) { + super(outerInstance); + } + + @Override + public void dispatchMessage(Message msg) { + final SuggestionsView suggestionsView = getOuterInstance(); + switch (msg.what) { + case MSG_HIDE_PREVIEW: + suggestionsView.hidePreview(); + break; + case MSG_UPDATE_SUGGESTION: + suggestionsView.updateSuggestions(); + break; + } + } + + public void postHidePreview() { + cancelHidePreview(); + sendMessageDelayed(obtainMessage(MSG_HIDE_PREVIEW), DELAY_HIDE_PREVIEW); + } + + public void cancelHidePreview() { + removeMessages(MSG_HIDE_PREVIEW); + } + + public void postUpdateSuggestions() { + cancelUpdateSuggestions(); + sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION), + DELAY_UPDATE_SUGGESTION); + } + + public void cancelUpdateSuggestions() { + removeMessages(MSG_UPDATE_SUGGESTION); + } + + public void cancelAllMessages() { + cancelHidePreview(); + cancelUpdateSuggestions(); + } + } + + private static class SuggestionsViewParams { + public final int mPadding; + public final int mDividerWidth; + public final int mSuggestionsStripHeight; + + protected final List mWords; + protected final List mDividers; + protected final List mInfos; + + protected SuggestionsViewParams(List words, List dividers, + List infos) { + mWords = words; + mDividers = dividers; + mInfos = infos; + + final TextView word = words.get(0); + final View divider = dividers.get(0); + mPadding = word.getCompoundPaddingLeft() + word.getCompoundPaddingRight(); + divider.measure( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); + mDividerWidth = divider.getMeasuredWidth(); + + final Resources res = word.getResources(); + mSuggestionsStripHeight = res.getDimensionPixelSize(R.dimen.suggestions_strip_height); + } + } + + private static class SuggestionsStripParams extends SuggestionsViewParams { + private static final int DEFAULT_SUGGESTIONS_COUNT_IN_STRIP = 3; + private static final int DEFAULT_CENTER_SUGGESTION_PERCENTILE = 40; + private static final int PUNCTUATIONS_IN_STRIP = 6; + + private final int mColorTypedWord; + private final int mColorAutoCorrect; + private final int mColorSuggested; + public final int mSuggestionsCountInStrip; + private final float mCenterSuggestionWeight; + private final int mCenterSuggestionIndex; + private final Drawable mMoreSuggestionsHint; + + private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); + private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); + private final CharacterStyle mInvertedForegroundColorSpan; + private final CharacterStyle mInvertedBackgroundColorSpan; + private static final int AUTO_CORRECT_BOLD = 0x01; + private static final int AUTO_CORRECT_UNDERLINE = 0x02; + private static final int AUTO_CORRECT_INVERT = 0x04; + private static final int VALID_TYPED_WORD_BOLD = 0x08; + + private final int mSuggestionStripOption; + + private final ArrayList mTexts = new ArrayList(); + + public boolean mMoreSuggestionsAvailable; + + public final TextView mWordToSaveView; + private final TextView mHintToSaveView; + private final CharSequence mHintToSaveText; + + public SuggestionsStripParams(Context context, AttributeSet attrs, int defStyle, + List words, List dividers, List infos) { + super(words, dividers, infos); + final TypedArray a = context.obtainStyledAttributes( + attrs, R.styleable.SuggestionsView, defStyle, R.style.SuggestionsViewStyle); + mSuggestionStripOption = a.getInt(R.styleable.SuggestionsView_suggestionStripOption, 0); + mColorTypedWord = a.getColor(R.styleable.SuggestionsView_colorTypedWord, 0); + mColorAutoCorrect = a.getColor(R.styleable.SuggestionsView_colorAutoCorrect, 0); + mColorSuggested = a.getColor(R.styleable.SuggestionsView_colorSuggested, 0); + mSuggestionsCountInStrip = a.getInt( + R.styleable.SuggestionsView_suggestionsCountInStrip, + DEFAULT_SUGGESTIONS_COUNT_IN_STRIP); + mCenterSuggestionWeight = a.getInt( + R.styleable.SuggestionsView_centerSuggestionPercentile, + DEFAULT_CENTER_SUGGESTION_PERCENTILE) / 100.0f; + a.recycle(); + + mCenterSuggestionIndex = mSuggestionsCountInStrip / 2; + final Resources res = context.getResources(); + mMoreSuggestionsHint = res.getDrawable(R.drawable.more_suggestions_hint); + + mInvertedForegroundColorSpan = new ForegroundColorSpan(mColorTypedWord ^ 0x00ffffff); + mInvertedBackgroundColorSpan = new BackgroundColorSpan(mColorTypedWord); + + final LayoutInflater inflater = LayoutInflater.from(context); + mWordToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); + mHintToSaveView = (TextView)inflater.inflate(R.layout.suggestion_word, null); + mHintToSaveText = context.getText(R.string.hint_add_to_dictionary); + } + + private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) { + final CharSequence word = suggestions.getWord(pos); + final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); + final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; + if (!isAutoCorrect && !isTypedWordValid) + return word; + + final int len = word.length(); + final Spannable spannedWord = new SpannableString(word); + final int option = mSuggestionStripOption; + if ((isAutoCorrect && (option & AUTO_CORRECT_BOLD) != 0) + || (isTypedWordValid && (option & VALID_TYPED_WORD_BOLD) != 0)) { + spannedWord.setSpan(BOLD_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + if (isAutoCorrect && (option & AUTO_CORRECT_UNDERLINE) != 0) { + spannedWord.setSpan(UNDERLINE_SPAN, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return spannedWord; + } + + private static boolean willAutoCorrect(SuggestedWords suggestions) { + return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; + } + + private int getWordPosition(int index, SuggestedWords suggestions) { + // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more + // suggestions. + final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; + if (index == mCenterSuggestionIndex) { + return centerPos; + } else if (index == centerPos) { + return mCenterSuggestionIndex; + } else { + return index; + } + } + + private int getSuggestionTextColor(int index, SuggestedWords suggestions, int pos) { + // TODO: Need to revisit this logic with bigram suggestions + final boolean isSuggested = (pos != 0); + + final int color; + if (index == mCenterSuggestionIndex && willAutoCorrect(suggestions)) { + color = mColorAutoCorrect; + } else if (isSuggested) { + color = mColorSuggested; + } else { + color = mColorTypedWord; + } + + final SuggestedWordInfo info = (pos < suggestions.size()) + ? suggestions.getInfo(pos) : null; + if (info != null && info.isObsoleteSuggestedWord()) { + return applyAlpha(color, 0.5f); + } else { + return color; + } + } + + private static int applyAlpha(final int color, final float alpha) { + final int newAlpha = (int)(Color.alpha(color) * alpha); + return Color.argb(newAlpha, Color.red(color), Color.green(color), Color.blue(color)); + } + + public CharSequence getInvertedText(CharSequence text) { + if ((mSuggestionStripOption & AUTO_CORRECT_INVERT) == 0) + return null; + final int len = text.length(); + final Spannable word = new SpannableString(text); + word.setSpan(mInvertedBackgroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + word.setSpan(mInvertedForegroundColorSpan, 0, len, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + return word; + } + + public void layout(SuggestedWords suggestions, ViewGroup stripView, ViewGroup placer, + int stripWidth) { + if (suggestions.isPunctuationSuggestions()) { + layoutPunctuationSuggestions(suggestions, stripView); + return; + } + + final int countInStrip = mSuggestionsCountInStrip; + setupTexts(suggestions, countInStrip); + mMoreSuggestionsAvailable = (suggestions.size() > countInStrip); + int x = 0; + for (int index = 0; index < countInStrip; index++) { + final int pos = getWordPosition(index, suggestions); + + if (index != 0) { + final View divider = mDividers.get(pos); + // Add divider if this isn't the left most suggestion in suggestions strip. + stripView.addView(divider); + x += divider.getMeasuredWidth(); + } + + final CharSequence styled = mTexts.get(pos); + final TextView word = mWords.get(pos); + if (index == mCenterSuggestionIndex && mMoreSuggestionsAvailable) { + // TODO: This "more suggestions hint" should have nicely designed icon. + word.setCompoundDrawablesWithIntrinsicBounds( + null, null, null, mMoreSuggestionsHint); + // HACK: To align with other TextView that has no compound drawables. + word.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight()); + } else { + word.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null); + } + + // Disable this suggestion if the suggestion is null or empty. + word.setEnabled(!TextUtils.isEmpty(styled)); + word.setTextColor(getSuggestionTextColor(index, suggestions, pos)); + final int width = getSuggestionWidth(index, stripWidth); + final CharSequence text = getEllipsizedText(styled, width, word.getPaint()); + final float scaleX = word.getTextScaleX(); + word.setText(text); // TextView.setText() resets text scale x to 1.0. + word.setTextScaleX(scaleX); + stripView.addView(word); + setLayoutWeight( + word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); + x += word.getMeasuredWidth(); + + if (DBG) { + final CharSequence debugInfo = getDebugInfo(suggestions, pos); + if (debugInfo != null) { + final TextView info = mInfos.get(pos); + info.setText(debugInfo); + placer.addView(info); + info.measure(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + final int infoWidth = info.getMeasuredWidth(); + final int y = info.getMeasuredHeight(); + FrameLayoutCompatUtils.placeViewAt( + info, x - infoWidth, y, infoWidth, info.getMeasuredHeight()); + } + } + } + } + + private int getSuggestionWidth(int index, int maxWidth) { + final int paddings = mPadding * mSuggestionsCountInStrip; + final int dividers = mDividerWidth * (mSuggestionsCountInStrip - 1); + final int availableWidth = maxWidth - paddings - dividers; + return (int)(availableWidth * getSuggestionWeight(index)); + } + + private float getSuggestionWeight(int index) { + if (index == mCenterSuggestionIndex) { + return mCenterSuggestionWeight; + } else { + // TODO: Revisit this for cases of 5 or more suggestions + return (1.0f - mCenterSuggestionWeight) / (mSuggestionsCountInStrip - 1); + } + } + + private void setupTexts(SuggestedWords suggestions, int countInStrip) { + mTexts.clear(); + final int count = Math.min(suggestions.size(), countInStrip); + for (int pos = 0; pos < count; pos++) { + final CharSequence styled = getStyledSuggestionWord(suggestions, pos); + mTexts.add(styled); + } + for (int pos = count; pos < countInStrip; pos++) { + // Make this inactive for touches in layout(). + mTexts.add(null); + } + } + + private void layoutPunctuationSuggestions(SuggestedWords suggestions, ViewGroup stripView) { + final int countInStrip = Math.min(suggestions.size(), PUNCTUATIONS_IN_STRIP); + for (int index = 0; index < countInStrip; index++) { + if (index != 0) { + // Add divider if this isn't the left most suggestion in suggestions strip. + stripView.addView(mDividers.get(index)); + } + + final TextView word = mWords.get(index); + word.setEnabled(true); + word.setTextColor(mColorTypedWord); + final CharSequence text = suggestions.getWord(index); + word.setText(text); + word.setTextScaleX(1.0f); + word.setCompoundDrawables(null, null, null, null); + stripView.addView(word); + setLayoutWeight(word, 1.0f, mSuggestionsStripHeight); + } + mMoreSuggestionsAvailable = false; + } + + public void layoutAddToDictionaryHint(CharSequence word, ViewGroup stripView, + int stripWidth) { + final int width = stripWidth - mDividerWidth - mPadding * 2; + + final TextView wordView = mWordToSaveView; + wordView.setTextColor(mColorTypedWord); + final int wordWidth = (int)(width * mCenterSuggestionWeight); + final CharSequence text = getEllipsizedText(word, wordWidth, wordView.getPaint()); + final float wordScaleX = wordView.getTextScaleX(); + wordView.setTag(word); + wordView.setText(text); + wordView.setTextScaleX(wordScaleX); + stripView.addView(wordView); + setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); + + stripView.addView(mDividers.get(0)); + + final TextView hintView = mHintToSaveView; + hintView.setTextColor(mColorAutoCorrect); + final int hintWidth = width - wordWidth; + final float hintScaleX = getTextScaleX(mHintToSaveText, hintWidth, hintView.getPaint()); + hintView.setText(mHintToSaveText); + hintView.setTextScaleX(hintScaleX); + stripView.addView(hintView); + setLayoutWeight( + hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); + } + } + + /** + * Construct a {@link SuggestionsView} for showing suggested words for completion. + * @param context + * @param attrs + */ + public SuggestionsView(Context context, AttributeSet attrs) { + this(context, attrs, R.attr.suggestionsViewStyle); + } + + public SuggestionsView(Context context, AttributeSet attrs, int defStyle) { + // Note: Up to version 10 (Gingerbread) of the API, LinearLayout doesn't have 3-argument + // constructor. + // TODO: Call 3-argument constructor, super(context, attrs, defStyle), when we abandon + // backward compatibility with the version 10 or earlier of the API. + super(context, attrs); + if (defStyle != R.attr.suggestionsViewStyle) { + throw new IllegalArgumentException( + "can't accept defStyle other than R.attr.suggestionsViewStyle: defStyle=" + + defStyle); + } + setBackgroundDrawable(LinearLayoutCompatUtils.getBackgroundDrawable( + context, attrs, defStyle, R.style.SuggestionsViewStyle)); + + final LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.suggestions_strip, this); + + mPreviewPopup = new PopupWindow(context); + mPreviewText = (TextView) inflater.inflate(R.layout.suggestion_preview, null); + mPreviewPopup.setWindowLayoutMode( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mPreviewPopup.setContentView(mPreviewText); + mPreviewPopup.setBackgroundDrawable(null); + + mSuggestionsPlacer = (ViewGroup)findViewById(R.id.suggestions_placer); + mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); + for (int pos = 0; pos < MAX_SUGGESTIONS; pos++) { + final TextView word = (TextView)inflater.inflate(R.layout.suggestion_word, null); + word.setTag(pos); + word.setOnClickListener(this); + word.setOnLongClickListener(this); + mWords.add(word); + final View divider = inflater.inflate(R.layout.suggestion_divider, null); + divider.setTag(pos); + divider.setOnClickListener(this); + mDividers.add(divider); + mInfos.add((TextView)inflater.inflate(R.layout.suggestion_info, null)); + } + + mStripParams = new SuggestionsStripParams(context, attrs, defStyle, mWords, mDividers, + mInfos); + mStripParams.mWordToSaveView.setOnClickListener(this); + + mMoreSuggestionsContainer = inflater.inflate(R.layout.more_suggestions, null); + mMoreSuggestionsView = (MoreSuggestionsView)mMoreSuggestionsContainer + .findViewById(R.id.more_suggestions_view); + mMoreSuggestionsBuilder = new MoreSuggestions.Builder(mMoreSuggestionsView); + mMoreSuggestionsWindow = new PopupWindow(context); + mMoreSuggestionsWindow.setWindowLayoutMode( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + mMoreSuggestionsWindow.setBackgroundDrawable(null); + } + + /** + * A connection back to the input method. + * @param listener + */ + public void setListener(Listener listener, View inputView) { + mListener = listener; + mKeyboardView = inputView.findViewById(R.id.keyboard_view); + } + + public void setSuggestions(SuggestedWords suggestions) { + if (suggestions == null) + return; + mSuggestions = suggestions; + if (mShowingAutoCorrectionInverted) { + mHandler.postUpdateSuggestions(); + } else { + updateSuggestions(); + } + } + + private void updateSuggestions() { + clear(); + if (mSuggestions.size() == 0) + return; + + mStripParams.layout(mSuggestions, mSuggestionsStrip, mSuggestionsPlacer, getWidth()); + } + + private static CharSequence getDebugInfo(SuggestedWords suggestions, int pos) { + if (DBG && pos < suggestions.size()) { + final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); + if (wordInfo != null) { + final CharSequence debugInfo = wordInfo.getDebugString(); + if (!TextUtils.isEmpty(debugInfo)) { + return debugInfo; + } + } + } + return null; + } + + private static void setLayoutWeight(View v, float weight, int height) { + final ViewGroup.LayoutParams lp = v.getLayoutParams(); + if (lp instanceof LinearLayout.LayoutParams) { + final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp; + llp.weight = weight; + llp.width = 0; + llp.height = height; + } + } + + private static float getTextScaleX(CharSequence text, int maxWidth, TextPaint paint) { + paint.setTextScaleX(1.0f); + final int width = getTextWidth(text, paint); + if (width <= maxWidth) { + return 1.0f; + } + return maxWidth / (float)width; + } + + private static CharSequence getEllipsizedText(CharSequence text, int maxWidth, + TextPaint paint) { + if (text == null) return null; + paint.setTextScaleX(1.0f); + final int width = getTextWidth(text, paint); + if (width <= maxWidth) { + return text; + } + final float scaleX = maxWidth / (float)width; + if (scaleX >= MIN_TEXT_XSCALE) { + paint.setTextScaleX(scaleX); + return text; + } + + // Note that TextUtils.ellipsize() use text-x-scale as 1.0 if ellipsize is needed. To get + // squeezed and ellipsized text, passes enlarged width (maxWidth / MIN_TEXT_XSCALE). + final CharSequence ellipsized = TextUtils.ellipsize( + text, paint, maxWidth / MIN_TEXT_XSCALE, TextUtils.TruncateAt.MIDDLE); + paint.setTextScaleX(MIN_TEXT_XSCALE); + return ellipsized; + } + + private static int getTextWidth(CharSequence text, TextPaint paint) { + if (TextUtils.isEmpty(text)) return 0; + final Typeface savedTypeface = paint.getTypeface(); + paint.setTypeface(getTextTypeface(text)); + final int len = text.length(); + final float[] widths = new float[len]; + final int count = paint.getTextWidths(text, 0, len, widths); + int width = 0; + for (int i = 0; i < count; i++) { + width += Math.round(widths[i] + 0.5f); + } + paint.setTypeface(savedTypeface); + return width; + } + + private static Typeface getTextTypeface(CharSequence text) { + if (!(text instanceof SpannableString)) + return Typeface.DEFAULT; + + final SpannableString ss = (SpannableString)text; + final StyleSpan[] styles = ss.getSpans(0, text.length(), StyleSpan.class); + if (styles.length == 0) + return Typeface.DEFAULT; + + switch (styles[0].getStyle()) { + case Typeface.BOLD: return Typeface.DEFAULT_BOLD; + // TODO: BOLD_ITALIC, ITALIC case? + default: return Typeface.DEFAULT; + } + } + + public void onAutoCorrectionInverted(CharSequence autoCorrectedWord) { + final CharSequence inverted = mStripParams.getInvertedText(autoCorrectedWord); + if (inverted == null) + return; + final TextView tv = mWords.get(1); + tv.setText(inverted); + mShowingAutoCorrectionInverted = true; + } + + public boolean isShowingAddToDictionaryHint() { + return mSuggestionsStrip.getChildCount() > 0 + && mSuggestionsStrip.getChildAt(0) == mStripParams.mWordToSaveView; + } + + public void showAddToDictionaryHint(CharSequence word) { + clear(); + mStripParams.layoutAddToDictionaryHint(word, mSuggestionsStrip, getWidth()); + } + + public boolean dismissAddToDictionaryHint() { + if (isShowingAddToDictionaryHint()) { + clear(); + return true; + } + return false; + } + + public SuggestedWords getSuggestions() { + return mSuggestions; + } + + public void clear() { + mShowingAutoCorrectionInverted = false; + mSuggestionsPlacer.removeAllViews(); + mSuggestionsPlacer.addView(mSuggestionsStrip); + mSuggestionsStrip.removeAllViews(); + mMoreSuggestionsWindow.dismiss(); + } + + private void hidePreview() { + mPreviewPopup.dismiss(); + } + + private void showPreview(View view, CharSequence word) { + if (TextUtils.isEmpty(word)) + return; + + final TextView previewText = mPreviewText; + previewText.setTextColor(mStripParams.mColorTypedWord); + previewText.setText(word); + previewText.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + final int[] offsetInWindow = new int[2]; + view.getLocationInWindow(offsetInWindow); + final int posX = offsetInWindow[0]; + final int posY = offsetInWindow[1] - previewText.getMeasuredHeight(); + final PopupWindow previewPopup = mPreviewPopup; + if (previewPopup.isShowing()) { + previewPopup.update(posX, posY, previewPopup.getWidth(), previewPopup.getHeight()); + } else { + previewPopup.showAtLocation(this, Gravity.NO_GRAVITY, posX, posY); + } + previewText.setVisibility(VISIBLE); + mHandler.postHidePreview(); + } + + private void addToDictionary(CharSequence word) { + if (mListener.addWordToDictionary(word.toString())) { + final CharSequence message = getContext().getString(R.string.added_word, word); + showPreview(mStripParams.mWordToSaveView, message); + } + } + + private final KeyboardActionListener mMoreSuggestionsListener = + new KeyboardActionListener.Adapter() { + @Override + public boolean onCustomRequest(int requestCode) { + final int index = requestCode; + final CharSequence word = mSuggestions.getWord(index); + mListener.pickSuggestionManually(index, word); + mMoreSuggestionsView.dismissMoreKeysPanel(); + return true; + } + + @Override + public void onCancelInput() { + mMoreSuggestionsView.dismissMoreKeysPanel(); + } + }; + + private final MoreKeysPanel.Controller mMoreSuggestionsController = + new MoreKeysPanel.Controller() { + @Override + public boolean dismissMoreKeysPanel() { + if (mMoreSuggestionsWindow.isShowing()) { + mMoreSuggestionsWindow.dismiss(); + return true; + } + return false; + } + }; + + @Override + public boolean onLongClick(View view) { + final SuggestionsStripParams params = mStripParams; + if (params.mMoreSuggestionsAvailable) { + final int stripWidth = getWidth(); + final View container = mMoreSuggestionsContainer; + final int maxWidth = stripWidth - container.getPaddingLeft() + - container.getPaddingRight(); + final DisplayMetrics dm = getContext().getResources().getDisplayMetrics(); + // TODO: Revise how we determine the height + final int maxHeight = dm.heightPixels - mKeyboardView.getHeight() - getHeight() * 3; + final MoreSuggestions.Builder builder = mMoreSuggestionsBuilder; + builder.layout(mSuggestions, params.mSuggestionsCountInStrip, maxWidth, maxHeight); + mMoreSuggestionsView.setKeyboard(builder.build()); + container.measure( + ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + + final MoreKeysPanel moreKeysPanel = mMoreSuggestionsView; + final int pointX = stripWidth / 2; + final int pointY = 0; + moreKeysPanel.showMoreKeysPanel( + this, mMoreSuggestionsController, pointX, pointY, + mMoreSuggestionsWindow, mMoreSuggestionsListener); + // TODO: Should figure out how to select the pointer tracker correctly. + final PointerTracker tracker = PointerTracker.getPointerTracker(0, moreKeysPanel); + final int translatedX = moreKeysPanel.translateX(tracker.getLastX()); + final int translatedY = moreKeysPanel.translateY(tracker.getLastY()); + tracker.onShowMoreKeysPanel( + translatedX, translatedY, SystemClock.uptimeMillis(), moreKeysPanel); + view.setPressed(false); + // TODO: Should gray out the keyboard here as well? + return true; + } + return false; + } + + @Override + public boolean dispatchTouchEvent(MotionEvent me) { + if (!mMoreSuggestionsWindow.isShowing()) { + return super.dispatchTouchEvent(me); + } + final int action = me.getAction(); + final long eventTime = me.getEventTime(); + final int index = me.getActionIndex(); + final int id = me.getPointerId(index); + final PointerTracker tracker = PointerTracker.getPointerTracker(id, mMoreSuggestionsView); + final int x = mMoreSuggestionsView.translateX((int)me.getX(index)); + final int y = mMoreSuggestionsView.translateY((int)me.getY(index)); + switch (action) { + case MotionEvent.ACTION_DOWN: + case MotionEvent.ACTION_POINTER_DOWN: + tracker.onDownEvent(x, y, eventTime, mMoreSuggestionsView); + break; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_POINTER_UP: + tracker.onUpEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_MOVE: + tracker.onMoveEvent(x, y, eventTime); + break; + case MotionEvent.ACTION_CANCEL: + tracker.onCancelEvent(x, y, eventTime); + break; + } + return true; + } + + @Override + public void onClick(View view) { + if (view == mStripParams.mWordToSaveView) { + addToDictionary((CharSequence)view.getTag()); + clear(); + return; + } + + final Object tag = view.getTag(); + if (!(tag instanceof Integer)) + return; + final int index = (Integer) tag; + if (index >= mSuggestions.size()) + return; + + final CharSequence word = mSuggestions.getWord(index); + mListener.pickSuggestionManually(index, word); + } + + @Override + public void onDetachedFromWindow() { + super.onDetachedFromWindow(); + mHandler.cancelAllMessages(); + hidePreview(); + } +} diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 60a4cfb38..6263ebefa 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -16,15 +16,7 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardId; - import android.content.Context; -import android.content.res.Configuration; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.AsyncTask; @@ -37,6 +29,13 @@ import android.text.format.DateUtils; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; +import com.android.inputmethod.compat.InputTypeCompatUtils; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; + import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; @@ -47,7 +46,6 @@ import java.io.PrintWriter; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; import java.util.Locale; @@ -175,21 +173,21 @@ public class Utils { // If user selected aggressive auto correction mode, there is no need to use the safety // net. if (suggest.isAggressiveAutoCorrectionMode()) return false; - CharSequence typedWord = suggestions.getWord(0); + final CharSequence typedWord = suggestions.getWord(0); // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, // we should not use net because relatively edit distance can be big. if (typedWord.length() < MINIMUM_SAFETY_NET_CHAR_LENGTH) return false; - CharSequence candidateWord = suggestions.getWord(1); + final CharSequence suggestionWord = suggestions.getWord(1); final int typedWordLength = typedWord.length(); final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2; - final int distance = Utils.editDistance(typedWord, candidateWord); + final int distance = Utils.editDistance(typedWord, suggestionWord); if (DBG) { Log.d(TAG, "Autocorrected edit distance = " + distance + ", " + maxEditDistanceOfNativeDictionary); } if (distance > maxEditDistanceOfNativeDictionary) { if (DBG) { - Log.d(TAG, "Safety net: before = " + typedWord + ", after = " + candidateWord); + Log.d(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord); Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. " + "Turning off auto-correction."); } @@ -717,7 +715,7 @@ public class Utils { // Don't cache suggestions.size(), since we may be removing items while (i < suggestions.size()) { final CharSequence cur = suggestions.get(i); - // Compare each candidate with each previous candidate + // Compare each suggestion with each previous suggestion for (int j = 0; j < i; j++) { CharSequence previous = suggestions.get(j); if (TextUtils.equals(cur, previous)) { -- cgit v1.2.3-83-g751a From f5ef30dfc6f4e436d35c38b6f7e32fbd24d54aab Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 9 Sep 2011 20:54:43 +0900 Subject: Have the spell checker honor case Bug: 5281103 Change-Id: I415c84dbb55f1eeb5deb9f248b4056881982ee13 --- java/src/com/android/inputmethod/latin/Utils.java | 11 +++- .../spellcheck/AndroidSpellCheckerService.java | 68 +++++++++++++++------- 2 files changed, 56 insertions(+), 23 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 6263ebefa..c35273edd 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -757,10 +757,19 @@ public class Utils { return toTitleCase(locale.getLanguage(), locale); } - private static String toTitleCase(String s, Locale locale) { + public static String toTitleCase(String s, Locale locale) { if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? return s; } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. return s.toUpperCase(locale).charAt(0) + s.substring(1); } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index ae47ab22b..3cf8788aa 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -55,6 +55,10 @@ public class AndroidSpellCheckerService extends SpellCheckerService { private static final boolean DBG = false; private static final int POOL_SIZE = 2; + private static final int CAPITALIZE_NONE = 0; // No caps, or mixed case + private static final int CAPITALIZE_FIRST = 1; // First only + private static final int CAPITALIZE_ALL = 2; // All caps + private final static String[] EMPTY_STRING_ARRAY = new String[0]; private final static SuggestionsInfo EMPTY_SUGGESTIONS_INFO = new SuggestionsInfo(0, EMPTY_STRING_ARRAY); @@ -139,7 +143,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { return true; } - public Result getResults(final CharSequence originalText, final double threshold) { + public Result getResults(final CharSequence originalText, final double threshold, + final int capitalizeType, final Locale locale) { final String[] gatheredSuggestions; final boolean looksLikeTypo; if (0 == mLength) { @@ -166,6 +171,19 @@ public class AndroidSpellCheckerService extends SpellCheckerService { } Collections.reverse(mSuggestions); Utils.removeDupes(mSuggestions); + if (CAPITALIZE_ALL == capitalizeType) { + for (int i = 0; i < mSuggestions.size(); ++i) { + // get(i) returns a CharSequence which is actually a String so .toString() + // should return the same object. + mSuggestions.set(i, mSuggestions.get(i).toString().toUpperCase(locale)); + } + } else if (CAPITALIZE_FIRST == capitalizeType) { + for (int i = 0; i < mSuggestions.size(); ++i) { + // Likewise + mSuggestions.set(i, Utils.toTitleCase(mSuggestions.get(i).toString(), + locale)); + } + } // This returns a String[], while toArray() returns an Object[] which cannot be cast // into a String[]. gatheredSuggestions = mSuggestions.toArray(EMPTY_STRING_ARRAY); @@ -226,6 +244,25 @@ public class AndroidSpellCheckerService extends SpellCheckerService { return new DictAndProximity(dictionaryCollection, proximityInfo); } + // This method assumes the text is not empty or null. + private static int getCapitalizationType(String text) { + // If the first char is not uppercase, then the word is either all lower case, + // and in either case we return CAPITALIZE_NONE. + if (!Character.isUpperCase(text.codePointAt(0))) return CAPITALIZE_NONE; + final int len = text.codePointCount(0, text.length()); + int capsCount = 1; + for (int i = 1; i < len; ++i) { + if (1 != capsCount && i != capsCount) break; + if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; + } + // We know the first char is upper case. So we want to test if either everything + // else is lower case, or if everything else is upper case. If the string is + // exactly one char long, then we will arrive here with capsCount 1, and this is + // correct, too. + if (1 == capsCount) return CAPITALIZE_FIRST; + return (len == capsCount ? CAPITALIZE_ALL : CAPITALIZE_NONE); + } + private static class AndroidSpellCheckerSession extends Session { // Immutable, but need the locale which is not available in the constructor yet private DictionaryPool mDictionaryPool; @@ -276,31 +313,18 @@ public class AndroidSpellCheckerService extends SpellCheckerService { WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); } + final int capitalizeType = getCapitalizationType(text); boolean isInDict = true; try { final DictAndProximity dictInfo = mDictionaryPool.take(); dictInfo.mDictionary.getWords(composer, suggestionsGatherer, dictInfo.mProximityInfo); isInDict = dictInfo.mDictionary.isValidWord(text); - if (!isInDict && Character.isUpperCase(text.codePointAt(0))) { - // If the first char is not uppercase, then the word is either all lower case, - // in which case we already tested it, or mixed case, in which case we don't - // want to test a lower-case version of it. Hence the test above. - // Also note that by isEmpty() test at the top of the method codePointAt(0) is - // guaranteed to be there. - final int len = text.codePointCount(0, text.length()); - int capsCount = 1; - for (int i = 1; i < len; ++i) { - if (1 != capsCount && i != capsCount) break; - if (Character.isUpperCase(text.codePointAt(i))) ++capsCount; - } - // We know the first char is upper case. So we want to test if either everything - // else is lower case, or if everything else is upper case. If the string is - // exactly one char long, then we will arrive here with capsCount 0, and this is - // correct, too. - if (1 == capsCount || len == capsCount) { - isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); - } + if (!isInDict && CAPITALIZE_NONE != capitalizeType) { + // We want to test the word again if it's all caps or first caps only. + // If it's fully down, we already tested it, if it's mixed case, we don't + // want to test a lowercase version of it. + isInDict = dictInfo.mDictionary.isValidWord(text.toLowerCase(mLocale)); } if (!mDictionaryPool.offer(dictInfo)) { Log.e(TAG, "Can't re-insert a dictionary into its pool"); @@ -310,8 +334,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService { return EMPTY_SUGGESTIONS_INFO; } - final SuggestionsGatherer.Result result = - suggestionsGatherer.getResults(text, mService.mTypoThreshold); + final SuggestionsGatherer.Result result = suggestionsGatherer.getResults(text, + mService.mTypoThreshold, capitalizeType, mLocale); if (DBG) { Log.i(TAG, "Spell checking results for " + text + " with suggestion limit " -- cgit v1.2.3-83-g751a From 433965784dca1a2cd801e1aab8c8258f64d8c7e0 Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 28 Sep 2011 20:11:05 +0900 Subject: add vibration duration settings Change-Id: I56a1a94df63160f367f866da759d7dd4fc428ed5 --- java/res/layout/vibration_settings_dialog.xml | 49 +++++++++++++++ java/res/values/donottranslate.xml | 1 + java/res/values/strings.xml | 2 + java/res/xml/prefs.xml | 3 + .../com/android/inputmethod/latin/LatinIME.java | 11 +--- .../com/android/inputmethod/latin/Settings.java | 69 +++++++++++++++++++++- java/src/com/android/inputmethod/latin/Utils.java | 18 ++++++ 7 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 java/res/layout/vibration_settings_dialog.xml (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/layout/vibration_settings_dialog.xml b/java/res/layout/vibration_settings_dialog.xml new file mode 100644 index 000000000..981ba9be0 --- /dev/null +++ b/java/res/layout/vibration_settings_dialog.xml @@ -0,0 +1,49 @@ + + + + + + + + + + diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml index 75e22ddd8..aefaec9ef 100644 --- a/java/res/values/donottranslate.xml +++ b/java/res/values/donottranslate.xml @@ -165,4 +165,5 @@ com.google.android.inputmethod.latin.dictionarypack com.google.android.inputmethod.latin.dictionarypack.DictionarySettingsActivity + ms diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 2f591fdf0..a1c1a9ffd 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -343,4 +343,6 @@ Usability study mode + + Vibration duration settings diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index 24de95f10..312af2888 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -125,6 +125,9 @@ android:summary="@string/enable_span_insert_summary" android:persistent="true" android:defaultValue="true" /> + diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 32649d5a1..48a1f8bd7 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2099,16 +2099,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void updateKeypressVibrationDuration() { - final String[] durationPerHardwareList = mResources.getStringArray( - R.array.keypress_vibration_durations); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : durationPerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - mKeypressVibrationDuration = - Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); - break; - } - } + mKeypressVibrationDuration = Utils.getCurrentVibrationDuration(mPrefs, mResources); } private void playKeyClick(int primaryCode) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index d706cd0a4..a2e896619 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -36,7 +36,10 @@ import android.preference.PreferenceScreen; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.util.Log; +import android.view.View; import android.view.inputmethod.EditorInfo; +import android.widget.SeekBar; +import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.android.inputmethod.compat.CompatUtils; @@ -89,6 +92,9 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; + public static final String PREF_VIBRATION_DURATION_SETTINGS = + "pref_vibration_duration_settings"; + // Dialog ids private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; @@ -335,6 +341,7 @@ public class Settings extends InputMethodSettingsActivity private boolean mVoiceOn; private AlertDialog mDialog; + private TextView mVibrationSettingsTextView; private boolean mOkClicked = false; private String mVoiceModeOff; @@ -475,6 +482,19 @@ public class Settings extends InputMethodSettingsActivity miscSettings.removePreference(pref); } } + + final PreferenceScreen vibrationSettingsPref = + (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS); + if (vibrationSettingsPref != null) { + vibrationSettingsPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference arg0) { + showVibrationSettingsDialog(); + return true; + } + }); + } } @SuppressWarnings("unused") @@ -621,4 +641,51 @@ public class Settings extends InputMethodSettingsActivity mVoicePreference.setValue(mVoiceModeOff); } } -} + + private void showVibrationSettingsDialog() { + final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); + final Activity context = getActivityInternal(); + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.prefs_vibration_duration_settings); + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + final int ms = Integer.valueOf(mVibrationSettingsTextView.getText().toString()); + sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); + } + }); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + final View v = context.getLayoutInflater().inflate( + R.layout.vibration_settings_dialog, null); + final int currentMs = Utils.getCurrentVibrationDuration( + getPreferenceManager().getSharedPreferences(), getResources()); + mVibrationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); + final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings); + sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { + final int tempMs = arg1; + mVibrationSettingsTextView.setText(String.valueOf(tempMs)); + } + + @Override + public void onStartTrackingTouch(SeekBar arg0) { + } + + @Override + public void onStopTrackingTouch(SeekBar arg0) { + final int tempMs = arg0.getProgress(); + VibratorCompatWrapper.getInstance(context).vibrate(tempMs); + } + }); + sb.setProgress(currentMs); + mVibrationSettingsTextView.setText(String.valueOf(currentMs)); + builder.setView(v); + builder.create().show(); + } +} \ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index c35273edd..771276567 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -17,9 +17,11 @@ package com.android.inputmethod.latin; import android.content.Context; +import android.content.SharedPreferences; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.AsyncTask; +import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -772,4 +774,20 @@ public class Utils { // - It also does not work with unicode surrogate code points. return s.toUpperCase(locale).charAt(0) + s.substring(1); } + + public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) { + final int ms = sp.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); + if (ms >= 0) { + return ms; + } + final String[] durationPerHardwareList = res.getStringArray( + R.array.keypress_vibration_durations); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : durationPerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1; + } } -- cgit v1.2.3-83-g751a From ec780e2868962bf17f0dfd35d36895f543bde40a Mon Sep 17 00:00:00 2001 From: satok Date: Wed, 28 Sep 2011 15:59:11 +0900 Subject: Put SuggestionSpan as the indicater of the auto-correction Bug: 5245468 Change-Id: Ia5609e1b3c69f5553e3632fbce60a55665a5b185 --- .../inputmethod/compat/SuggestionSpanUtils.java | 23 ++++++++++++++++++++++ .../com/android/inputmethod/latin/LatinIME.java | 11 +++++++++++ .../android/inputmethod/latin/SuggestionsView.java | 10 +++------- java/src/com/android/inputmethod/latin/Utils.java | 4 ++++ 4 files changed, 41 insertions(+), 7 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index 5c54fa548..876bd65f6 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -24,18 +24,22 @@ import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; import android.text.TextUtils; +import android.util.Log; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.Locale; public class SuggestionSpanUtils { + private static final String TAG = SuggestionSpanUtils.class.getSimpleName(); // TODO: Use reflection to get field values public static final String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED"; public static final String SUGGESTION_SPAN_PICKED_AFTER = "after"; public static final String SUGGESTION_SPAN_PICKED_BEFORE = "before"; public static final String SUGGESTION_SPAN_PICKED_HASHCODE = "hashcode"; + // TODO: Use the API constant after it gets public. + public static final int FLAG_AUTO_CORRECTION = 0x0004; public static final int SUGGESTION_MAX_SIZE = 5; public static final boolean SUGGESTION_SPAN_IS_SUPPORTED; @@ -50,6 +54,25 @@ public class SuggestionSpanUtils { CLASS_SuggestionSpan != null && CONSTRUCTOR_SuggestionSpan != null; } + public static CharSequence getTextWithAutoCorrectionIndicatorUnderline( + Context context, CharSequence text) { + if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null) { + return text; + } + final Spannable spannable = text instanceof Spannable + ? (Spannable) text : new SpannableString(text); + final Object[] args = + { context, null, new String[] {}, FLAG_AUTO_CORRECTION, + (Class) SuggestionSpanPickedNotificationReceiver.class }; + final Object ss = CompatUtils.newInstance(CONSTRUCTOR_SuggestionSpan, args); + if (ss == null) { + Log.w(TAG, "Suggestion span was not created."); + return text; + } + spannable.setSpan(ss, 0, text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + return spannable; + } + public static CharSequence getTextWithSuggestionSpan(Context context, CharSequence pickedWord, SuggestedWords suggestedWords) { if (TextUtils.isEmpty(pickedWord) || CONSTRUCTOR_SuggestionSpan == null diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 36e97af11..c5f336b3f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1601,6 +1601,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.onAutoCorrectionStateChanged( words.hasWordAboveAutoCorrectionScoreThreshold()); } + + // Put a blue underline to a word in TextView which will be auto-corrected. + final InputConnection ic = getCurrentInputConnection(); + if (ic != null && Utils.willAutoCorrect(words)) { + final CharSequence textWithUnderline = + SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline( + this, mComposingStringBuilder); + if (!TextUtils.isEmpty(textWithUnderline)) { + ic.setComposingText(textWithUnderline, 1); + } + } } public void updateSuggestions() { diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java index fe54f4ae1..3271b8253 100644 --- a/java/src/com/android/inputmethod/latin/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java @@ -260,7 +260,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, private CharSequence getStyledSuggestionWord(SuggestedWords suggestions, int pos) { final CharSequence word = suggestions.getWord(pos); - final boolean isAutoCorrect = pos == 1 && willAutoCorrect(suggestions); + final boolean isAutoCorrect = pos == 1 && Utils.willAutoCorrect(suggestions); final boolean isTypedWordValid = pos == 0 && suggestions.mTypedWordValid; if (!isAutoCorrect && !isTypedWordValid) return word; @@ -278,14 +278,10 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, return spannedWord; } - private static boolean willAutoCorrect(SuggestedWords suggestions) { - return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; - } - private int getWordPosition(int index, SuggestedWords suggestions) { // TODO: This works for 3 suggestions. Revisit this algorithm when there are 5 or more // suggestions. - final int centerPos = willAutoCorrect(suggestions) ? 1 : 0; + final int centerPos = Utils.willAutoCorrect(suggestions) ? 1 : 0; if (index == mCenterSuggestionIndex) { return centerPos; } else if (index == centerPos) { @@ -300,7 +296,7 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, final boolean isSuggested = (pos != 0); final int color; - if (index == mCenterSuggestionIndex && willAutoCorrect(suggestions)) { + if (index == mCenterSuggestionIndex && Utils.willAutoCorrect(suggestions)) { color = mColorAutoCorrect; } else if (isSuggested) { color = mColorSuggested; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 771276567..de2930460 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -790,4 +790,8 @@ public class Utils { } return -1; } + + public static boolean willAutoCorrect(SuggestedWords suggestions) { + return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; + } } -- cgit v1.2.3-83-g751a From 79c0acf51984256d640b38ea3c394f308cc3b314 Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 11 Oct 2011 16:39:11 +0900 Subject: Add a settings to change the sound effect volume Bug: 5345401 Bug: 5402541 Change-Id: I1e653573a3362160104b77388d6cbd1700424649 --- java/res/layout/sound_effect_volume_dialog.xml | 44 +++++++ java/res/values/strings.xml | 6 +- java/res/xml/prefs.xml | 5 +- .../com/android/inputmethod/latin/LatinIME.java | 12 +- .../com/android/inputmethod/latin/Settings.java | 139 ++++++++++++++++++--- java/src/com/android/inputmethod/latin/Utils.java | 18 ++- 6 files changed, 190 insertions(+), 34 deletions(-) create mode 100644 java/res/layout/sound_effect_volume_dialog.xml (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/layout/sound_effect_volume_dialog.xml b/java/res/layout/sound_effect_volume_dialog.xml new file mode 100644 index 000000000..c5b2f10e2 --- /dev/null +++ b/java/res/layout/sound_effect_volume_dialog.xml @@ -0,0 +1,44 @@ + + + + + + + + + diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index 8bc97f66e..e00547a62 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -342,6 +342,8 @@ Usability study mode - - Vibration duration settings + + Keypress vibration duration settings + + Keypress sound volume settings diff --git a/java/res/xml/prefs.xml b/java/res/xml/prefs.xml index b54df2686..dcaa2029c 100644 --- a/java/res/xml/prefs.xml +++ b/java/res/xml/prefs.xml @@ -121,7 +121,10 @@ android:defaultValue="true" /> + android:title="@string/prefs_keypress_vibration_duration_settings"/> + diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 958092bc7..28d920557 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -28,7 +28,6 @@ import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; -import android.os.Build; import android.os.Debug; import android.os.Message; import android.os.SystemClock; @@ -2097,16 +2096,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } }; - // update sound effect volume + // update keypress sound volume private void updateSoundEffectVolume() { - final String[] volumePerHardwareList = mResources.getStringArray(R.array.keypress_volumes); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : volumePerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - mFxVolume = Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); - break; - } - } + mFxVolume = Utils.getCurrentKeypressSoundVolume(mPrefs, mResources); } // update flags for silent mode diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index d9508f4c1..eeb0299b1 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -26,6 +26,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Resources; +import android.media.AudioManager; import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.ListPreference; @@ -91,9 +92,11 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; - public static final String PREF_VIBRATION_DURATION_SETTINGS = + public static final String PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS = "pref_vibration_duration_settings"; + public static final String PREF_KEYPRESS_SOUND_VOLUME = + "pref_keypress_sound_volume"; // Dialog ids private static final int VOICE_INPUT_CONFIRM_DIALOG = 0; @@ -327,7 +330,8 @@ public class Settings extends InputMethodSettingsActivity } private PreferenceScreen mInputLanguageSelection; - private PreferenceScreen mVibrationDurationSettingsPref; + private PreferenceScreen mKeypressVibrationDurationSettingsPref; + private PreferenceScreen mKeypressSoundVolumeSettingsPref; private ListPreference mVoicePreference; private CheckBoxPreference mShowSettingsKeyPreference; private ListPreference mShowCorrectionSuggestionsPreference; @@ -341,7 +345,8 @@ public class Settings extends InputMethodSettingsActivity private boolean mVoiceOn; private AlertDialog mDialog; - private TextView mVibrationSettingsTextView; + private TextView mKeypressVibrationDurationSettingsTextView; + private TextView mKeypressSoundVolumeSettingsTextView; private boolean mOkClicked = false; private String mVoiceModeOff; @@ -477,19 +482,34 @@ public class Settings extends InputMethodSettingsActivity } } - mVibrationDurationSettingsPref = - (PreferenceScreen) findPreference(PREF_VIBRATION_DURATION_SETTINGS); - if (mVibrationDurationSettingsPref != null) { - mVibrationDurationSettingsPref.setOnPreferenceClickListener( + mKeypressVibrationDurationSettingsPref = + (PreferenceScreen) findPreference(PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS); + if (mKeypressVibrationDurationSettingsPref != null) { + mKeypressVibrationDurationSettingsPref.setOnPreferenceClickListener( new OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference arg0) { - showVibrationSettingsDialog(); + showKeypressVibrationDurationSettingsDialog(); return true; } }); - updateVibrationDurationSettingsSummary(prefs, res); + updateKeypressVibrationDurationSettingsSummary(prefs, res); } + + mKeypressSoundVolumeSettingsPref = + (PreferenceScreen) findPreference(PREF_KEYPRESS_SOUND_VOLUME); + if (mKeypressSoundVolumeSettingsPref != null) { + mKeypressSoundVolumeSettingsPref.setOnPreferenceClickListener( + new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference arg0) { + showKeypressSoundVolumeSettingDialog(); + return true; + } + }); + updateKeypressSoundVolumeSummary(prefs, res); + } + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); } @SuppressWarnings("unused") @@ -537,6 +557,7 @@ public class Settings extends InputMethodSettingsActivity updateVoiceModeSummary(); updateShowCorrectionSuggestionsSummary(); updateKeyPreviewPopupDelaySummary(); + refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, getResources()); } @Override @@ -637,26 +658,44 @@ public class Settings extends InputMethodSettingsActivity } } - private void updateVibrationDurationSettingsSummary(SharedPreferences sp, Resources res) { - if (mVibrationDurationSettingsPref != null) { - mVibrationDurationSettingsPref.setSummary( + private void refreshEnablingsOfKeypressSoundAndVibrationSettings( + SharedPreferences sp, Resources res) { + if (mKeypressVibrationDurationSettingsPref != null) { + final boolean hasVibrator = VibratorCompatWrapper.getInstance(this).hasVibrator(); + final boolean vibrateOn = hasVibrator && sp.getBoolean(Settings.PREF_VIBRATE_ON, + res.getBoolean(R.bool.config_default_vibration_enabled)); + mKeypressVibrationDurationSettingsPref.setEnabled(vibrateOn); + } + + if (mKeypressSoundVolumeSettingsPref != null) { + final boolean soundOn = sp.getBoolean(Settings.PREF_SOUND_ON, + res.getBoolean(R.bool.config_default_sound_enabled)); + mKeypressSoundVolumeSettingsPref.setEnabled(soundOn); + } + } + + private void updateKeypressVibrationDurationSettingsSummary( + SharedPreferences sp, Resources res) { + if (mKeypressVibrationDurationSettingsPref != null) { + mKeypressVibrationDurationSettingsPref.setSummary( Utils.getCurrentVibrationDuration(sp, res) + res.getString(R.string.settings_ms)); } } - private void showVibrationSettingsDialog() { + private void showKeypressVibrationDurationSettingsDialog() { final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); final Activity context = getActivityInternal(); final Resources res = context.getResources(); final AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setTitle(R.string.prefs_vibration_duration_settings); + builder.setTitle(R.string.prefs_keypress_vibration_duration_settings); builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int whichButton) { - final int ms = Integer.valueOf(mVibrationSettingsTextView.getText().toString()); - sp.edit().putInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, ms).apply(); - updateVibrationDurationSettingsSummary(sp, res); + final int ms = Integer.valueOf( + mKeypressVibrationDurationSettingsTextView.getText().toString()); + sp.edit().putInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, ms).apply(); + updateKeypressVibrationDurationSettingsSummary(sp, res); } }); builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @@ -669,13 +708,13 @@ public class Settings extends InputMethodSettingsActivity R.layout.vibration_settings_dialog, null); final int currentMs = Utils.getCurrentVibrationDuration( getPreferenceManager().getSharedPreferences(), getResources()); - mVibrationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); + mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings); sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { final int tempMs = arg1; - mVibrationSettingsTextView.setText(String.valueOf(tempMs)); + mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(tempMs)); } @Override @@ -689,7 +728,67 @@ public class Settings extends InputMethodSettingsActivity } }); sb.setProgress(currentMs); - mVibrationSettingsTextView.setText(String.valueOf(currentMs)); + mKeypressVibrationDurationSettingsTextView.setText(String.valueOf(currentMs)); + builder.setView(v); + builder.create().show(); + } + + private void updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res) { + if (mKeypressSoundVolumeSettingsPref != null) { + mKeypressSoundVolumeSettingsPref.setSummary( + String.valueOf((int)(Utils.getCurrentKeypressSoundVolume(sp, res) * 100))); + } + } + + private void showKeypressSoundVolumeSettingDialog() { + final AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE); + final SharedPreferences sp = getPreferenceManager().getSharedPreferences(); + final Activity context = getActivityInternal(); + final Resources res = context.getResources(); + final AlertDialog.Builder builder = new AlertDialog.Builder(context); + builder.setTitle(R.string.prefs_keypress_sound_volume_settings); + builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + final float volume = + ((float)Integer.valueOf( + mKeypressSoundVolumeSettingsTextView.getText().toString())) / 100; + sp.edit().putFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, volume).apply(); + updateKeypressSoundVolumeSummary(sp, res); + } + }); + builder.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int whichButton) { + dialog.dismiss(); + } + }); + final View v = context.getLayoutInflater().inflate( + R.layout.sound_effect_volume_dialog, null); + final int currentVolumeInt = (int)(Utils.getCurrentKeypressSoundVolume( + getPreferenceManager().getSharedPreferences(), getResources()) * 100); + mKeypressSoundVolumeSettingsTextView = + (TextView)v.findViewById(R.id.sound_effect_volume_value); + final SeekBar sb = (SeekBar)v.findViewById(R.id.sound_effect_volume_bar); + sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { + @Override + public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) { + final int tempVolume = arg1; + mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(tempVolume)); + } + + @Override + public void onStartTrackingTouch(SeekBar arg0) { + } + + @Override + public void onStopTrackingTouch(SeekBar arg0) { + final float tempVolume = ((float)arg0.getProgress()) / 100; + am.playSoundEffect(AudioManager.FX_KEYPRESS_STANDARD, tempVolume); + } + }); + sb.setProgress(currentVolumeInt); + mKeypressSoundVolumeSettingsTextView.setText(String.valueOf(currentVolumeInt)); builder.setView(v); builder.create().show(); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index de2930460..34c8c894b 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -776,7 +776,7 @@ public class Utils { } public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) { - final int ms = sp.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, -1); + final int ms = sp.getInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, -1); if (ms >= 0) { return ms; } @@ -791,6 +791,22 @@ public class Utils { return -1; } + public static float getCurrentKeypressSoundVolume(SharedPreferences sp, Resources res) { + final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + if (volume >= 0) { + return volume; + } + + final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : volumePerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1.0f; + } + public static boolean willAutoCorrect(SuggestedWords suggestions) { return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; } -- cgit v1.2.3-83-g751a From 2aa1dd45c44295e2f7e8ece1b520032d86b9f908 Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 13 Oct 2011 14:25:26 +0900 Subject: Fix the safety net Bug: 5453150 Change-Id: I5990feb2622738988bf29843c6bcdb9cbf8bbf33 --- .../src/com/android/inputmethod/latin/LatinIME.java | 7 ++++++- .../android/inputmethod/latin/SuggestedWords.java | 21 ++++++++++++++++----- .../android/inputmethod/latin/SuggestionsView.java | 6 ++++++ java/src/com/android/inputmethod/latin/Utils.java | 14 +++++++++----- 4 files changed, 37 insertions(+), 11 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 3c878d0a8..2fd85894c 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1722,9 +1722,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } public void showSuggestions(SuggestedWords suggestedWords, CharSequence typedWord) { + final boolean shouldBlockAutoCorrectionBySafetyNet = + Utils.shouldBlockAutoCorrectionBySafetyNet(suggestedWords, mSuggest); + if (shouldBlockAutoCorrectionBySafetyNet) { + suggestedWords.setShouldBlockAutoCorrection(); + } setSuggestions(suggestedWords); if (suggestedWords.size() > 0) { - if (Utils.shouldBlockedBySafetyNetForAutoCorrection(suggestedWords, mSuggest)) { + if (shouldBlockAutoCorrectionBySafetyNet) { mBestWord = typedWord; } else if (suggestedWords.hasAutoCorrectionWord()) { mBestWord = suggestedWords.getWord(1); diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 005db36bd..ed6359cfa 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -29,12 +29,13 @@ public class SuggestedWords { public final List mWords; public final boolean mTypedWordValid; - public final boolean mHasMinimalSuggestion; + public final boolean mHasAutoCorrectionCandidate; public final boolean mIsPunctuationSuggestions; private final List mSuggestedWordInfoList; + private boolean mShouldBlockAutoCorrection; private SuggestedWords(List words, boolean typedWordValid, - boolean hasMinimalSuggestion, boolean isPunctuationSuggestions, + boolean hasAutoCorrectionCandidate, boolean isPunctuationSuggestions, List suggestedWordInfoList) { if (words != null) { mWords = words; @@ -42,9 +43,10 @@ public class SuggestedWords { mWords = Collections.emptyList(); } mTypedWordValid = typedWordValid; - mHasMinimalSuggestion = hasMinimalSuggestion; + mHasAutoCorrectionCandidate = hasAutoCorrectionCandidate; mIsPunctuationSuggestions = isPunctuationSuggestions; mSuggestedWordInfoList = suggestedWordInfoList; + mShouldBlockAutoCorrection = false; } public int size() { @@ -60,17 +62,25 @@ public class SuggestedWords { } public boolean hasAutoCorrectionWord() { - return mHasMinimalSuggestion && size() > 1 && !mTypedWordValid; + return mHasAutoCorrectionCandidate && size() > 1 && !mTypedWordValid; } public boolean hasWordAboveAutoCorrectionScoreThreshold() { - return mHasMinimalSuggestion && ((size() > 1 && !mTypedWordValid) || mTypedWordValid); + return mHasAutoCorrectionCandidate && ((size() > 1 && !mTypedWordValid) || mTypedWordValid); } public boolean isPunctuationSuggestions() { return mIsPunctuationSuggestions; } + public void setShouldBlockAutoCorrection() { + mShouldBlockAutoCorrection = true; + } + + public boolean shouldBlockAutoCorrection() { + return mShouldBlockAutoCorrection; + } + public static class Builder { private List mWords = new ArrayList(); private boolean mTypedWordValid; @@ -176,6 +186,7 @@ public class SuggestedWords { return mWords.get(pos); } + @Override public String toString() { // Pretty-print method to help debug final StringBuilder sb = new StringBuilder("StringBuilder: mTypedWordValid = " diff --git a/java/src/com/android/inputmethod/latin/SuggestionsView.java b/java/src/com/android/inputmethod/latin/SuggestionsView.java index 3271b8253..937c2c9ff 100644 --- a/java/src/com/android/inputmethod/latin/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/SuggestionsView.java @@ -303,6 +303,12 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, } else { color = mColorTypedWord; } + if (LatinImeLogger.sDBG) { + if (index == mCenterSuggestionIndex && suggestions.mHasAutoCorrectionCandidate + && suggestions.shouldBlockAutoCorrection()) { + return 0xFFFF0000; + } + } final SuggestedWordInfo info = (pos < suggestions.size()) ? suggestions.getInfo(pos) : null; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index de2930460..f6343f1d7 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -167,7 +167,9 @@ public class Utils { throw new RuntimeException("Can not find input method id for " + packageName); } - public static boolean shouldBlockedBySafetyNetForAutoCorrection(SuggestedWords suggestions, + // TODO: Resolve the inconsistencies between the native auto correction algorithms and + // this safety net + public static boolean shouldBlockAutoCorrectionBySafetyNet(SuggestedWords suggestions, Suggest suggest) { // Safety net for auto correction. // Actually if we hit this safety net, it's actually a bug. @@ -181,7 +183,8 @@ public class Utils { if (typedWord.length() < MINIMUM_SAFETY_NET_CHAR_LENGTH) return false; final CharSequence suggestionWord = suggestions.getWord(1); final int typedWordLength = typedWord.length(); - final int maxEditDistanceOfNativeDictionary = typedWordLength < 5 ? 2 : typedWordLength / 2; + final int maxEditDistanceOfNativeDictionary = + (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; final int distance = Utils.editDistance(typedWord, suggestionWord); if (DBG) { Log.d(TAG, "Autocorrected edit distance = " + distance @@ -189,8 +192,8 @@ public class Utils { } if (distance > maxEditDistanceOfNativeDictionary) { if (DBG) { - Log.d(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord); - Log.w(TAG, "(Error) The edit distance of this correction exceeds limit. " + Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord); + Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. " + "Turning off auto-correction."); } return true; @@ -792,6 +795,7 @@ public class Utils { } public static boolean willAutoCorrect(SuggestedWords suggestions) { - return !suggestions.mTypedWordValid && suggestions.mHasMinimalSuggestion; + return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate + && !suggestions.shouldBlockAutoCorrection(); } } -- cgit v1.2.3-83-g751a From 8fbf29e2d54027a17993cd0d4ad486e3454b56f6 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Fri, 28 Oct 2011 13:31:31 +0900 Subject: Make some private method static Change-Id: Ia23765268be0ef89d7fe7c3f5372ed32d6615765 --- .../compat/InputMethodManagerCompatWrapper.java | 3 +-- java/src/com/android/inputmethod/keyboard/Key.java | 2 +- .../android/inputmethod/keyboard/internal/KeyStyles.java | 2 +- .../com/android/inputmethod/latin/AutoCorrection.java | 2 +- java/src/com/android/inputmethod/latin/LatinIME.java | 16 ++++++---------- java/src/com/android/inputmethod/latin/Suggest.java | 5 +++-- .../android/inputmethod/latin/UserBigramDictionary.java | 8 ++++---- .../android/inputmethod/latin/UserUnigramDictionary.java | 4 ++-- java/src/com/android/inputmethod/latin/Utils.java | 4 ++-- java/src/com/android/inputmethod/latin/WordComposer.java | 2 +- .../latin/spellcheck/AndroidSpellCheckerService.java | 2 +- 11 files changed, 23 insertions(+), 27 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 51dc4cd37..0e5f8c80a 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -153,8 +153,7 @@ public class InputMethodManagerCompatWrapper { return Utils.getInputMethodInfo(this, mLatinImePackageName); } - @SuppressWarnings("unused") - private InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { + private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { if (VOICE_MODE.equals(mode) && !FORCE_ENABLE_VOICE_EVEN_WITH_NO_VOICE_SUBTYPES) return null; Locale inputLocale = SubtypeSwitcher.getInstance().getInputLocale(); diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index f1ae0b313..f2014b771 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -223,7 +223,7 @@ public class Key { if (style == null) throw new ParseException("Unknown key style: " + styleName, parser); } else { - style = keyStyles.getEmptyKeyStyle(); + style = KeyStyles.getEmptyKeyStyle(); } final float keyXPos = row.getKeyX(keyAttr); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java index b385b7a04..39fb521ea 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyStyles.java @@ -235,7 +235,7 @@ public class KeyStyles { return mStyles.get(styleName); } - public KeyStyle getEmptyKeyStyle() { + public static KeyStyle getEmptyKeyStyle() { return EMPTY_KEY_STYLE; } } diff --git a/java/src/com/android/inputmethod/latin/AutoCorrection.java b/java/src/com/android/inputmethod/latin/AutoCorrection.java index 485ec511f..cd066a3d1 100644 --- a/java/src/com/android/inputmethod/latin/AutoCorrection.java +++ b/java/src/com/android/inputmethod/latin/AutoCorrection.java @@ -98,7 +98,7 @@ public class AutoCorrection { return whiteListedWord != null; } - private boolean hasAutoCorrectionForTypedWord(Map dictionaries, + private static boolean hasAutoCorrectionForTypedWord(Map dictionaries, WordComposer wordComposer, ArrayList suggestions, CharSequence typedWord, int correctionMode) { if (TextUtils.isEmpty(typedWord)) return false; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 1666fc191..70e0a1852 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1178,7 +1178,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null - private void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { + private static void maybeRemovePreviousPeriod(final InputConnection ic, CharSequence text) { // When the text's first character is '.', remove the previous period // if there is one. final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); @@ -1190,7 +1190,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" may be null - private void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { + private static void removeTrailingSpaceWhileInBatchEdit(final InputConnection ic) { if (ic == null) return; final CharSequence lastOne = ic.getTextBeforeCursor(1, 0); if (lastOne != null && lastOne.length() == 1 @@ -1208,12 +1208,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } - private boolean isAlphabet(int code) { - if (Character.isLetter(code)) { - return true; - } else { - return false; - } + private static boolean isAlphabet(int code) { + return Character.isLetter(code); } private void onSettingsKeyPressed() { @@ -2075,7 +2071,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // "ic" must not be null - private boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { + private static boolean sameAsTextBeforeCursor(final InputConnection ic, CharSequence text) { CharSequence beforeText = ic.getTextBeforeCursor(text.length(), 0); return TextUtils.equals(text, beforeText); } @@ -2129,7 +2125,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return true; } - private boolean revertSwapPunctuation(final InputConnection ic) { + private static boolean revertSwapPunctuation(final InputConnection ic) { // Here we test whether we indeed have a space and something else before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index caa5aac51..97e91745c 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -144,7 +144,7 @@ public class Suggest implements Dictionary.WordCallback { initWhitelistAndAutocorrectAndPool(context, locale); } - private void addOrReplaceDictionary(Map dictionaries, String key, + private static void addOrReplaceDictionary(Map dictionaries, String key, Dictionary dict) { final Dictionary oldDict = (dict == null) ? dictionaries.remove(key) @@ -518,7 +518,8 @@ public class Suggest implements Dictionary.WordCallback { return -1; } - private void collectGarbage(ArrayList suggestions, int prefMaxSuggestions) { + private static void collectGarbage(ArrayList suggestions, + int prefMaxSuggestions) { int poolSize = StringBuilderPool.getSize(); int garbageSize = suggestions.size(); while (poolSize < prefMaxSuggestions && garbageSize > 0) { diff --git a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java index 9e656675e..3a1af9311 100644 --- a/java/src/com/android/inputmethod/latin/UserBigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBigramDictionary.java @@ -238,7 +238,7 @@ public class UserBigramDictionary extends ExpandableDictionary { /** * Query the database */ - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); // main INNER JOIN frequency ON (main._id=freq.pair_id) @@ -310,7 +310,7 @@ public class UserBigramDictionary extends ExpandableDictionary { } /** Prune any old data if the database is getting too big. */ - private void checkPruneData(SQLiteDatabase db) { + private static void checkPruneData(SQLiteDatabase db) { db.execSQL("PRAGMA foreign_keys = ON;"); Cursor c = db.query(FREQ_TABLE_NAME, new String[] { FREQ_COLUMN_PAIR_ID }, null, null, null, null, null); @@ -380,7 +380,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word1, String word2, String locale) { + private static ContentValues getContentValues(String word1, String word2, String locale) { ContentValues values = new ContentValues(3); values.put(MAIN_COLUMN_WORD1, word1); values.put(MAIN_COLUMN_WORD2, word2); @@ -388,7 +388,7 @@ public class UserBigramDictionary extends ExpandableDictionary { return values; } - private ContentValues getFrequencyContentValues(int pairId, int frequency) { + private static ContentValues getFrequencyContentValues(int pairId, int frequency) { ContentValues values = new ContentValues(2); values.put(FREQ_COLUMN_PAIR_ID, pairId); values.put(FREQ_COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java index e41230b3c..de7cb5716 100644 --- a/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserUnigramDictionary.java @@ -206,7 +206,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { } } - private Cursor query(String selection, String[] selectionArgs) { + private static Cursor query(String selection, String[] selectionArgs) { SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); qb.setTables(USER_UNIGRAM_DICT_TABLE_NAME); qb.setProjectionMap(sDictProjectionMap); @@ -251,7 +251,7 @@ public class UserUnigramDictionary extends ExpandableDictionary { return null; } - private ContentValues getContentValues(String word, int frequency, String locale) { + private static ContentValues getContentValues(String word, int frequency, String locale) { ContentValues values = new ContentValues(4); values.put(COLUMN_WORD, word); values.put(COLUMN_FREQUENCY, frequency); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index b29ff1975..3d0aa09f1 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -242,7 +242,7 @@ public class Utils { UsabilityStudyLogUtils.getInstance().init(context); return sRingCharBuffer; } - private int normalize(int in) { + private static int normalize(int in) { int ret = in % BUFSIZE; return ret < 0 ? ret + BUFSIZE : ret; } @@ -465,7 +465,7 @@ public class Utils { } } - public void writeBackSpace() { + public static void writeBackSpace() { UsabilityStudyLogUtils.getInstance().write("\t0\t0"); } diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index adc5637f6..7f3a54244 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -135,7 +135,7 @@ public class WordComposer { * @param primaryCode the preferred character * @param codes array of codes based on distance from touch point */ - private void correctPrimaryJuxtapos(int primaryCode, int[] codes) { + private static void correctPrimaryJuxtapos(int primaryCode, int[] codes) { if (codes.length < 2) return; if (codes[0] > 0 && codes[1] > 0 && codes[0] != primaryCode && codes[1] == primaryCode) { codes[1] = codes[0]; diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 095c2c51c..5d296f892 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -368,7 +368,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService { * @param text the string to evaluate. * @return true if we should filter this text out, false otherwise */ - private boolean shouldFilterOut(final String text) { + private static boolean shouldFilterOut(final String text) { if (TextUtils.isEmpty(text) || text.length() <= 1) return true; // TODO: check if an equivalent processing can't be done more quickly with a -- cgit v1.2.3-83-g751a From ed432962175a6f783428bbdcd7168d20097ec05d Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 8 Dec 2011 22:14:54 +0900 Subject: Move settings method from Utils to SettingsValues Change-Id: I633378a41f63cd492b8c9345d550e07254df5e5a --- .../com/android/inputmethod/latin/LatinIME.java | 4 +-- .../com/android/inputmethod/latin/Settings.java | 10 +++--- .../android/inputmethod/latin/SettingsValues.java | 36 +++++++++++++++++++++- java/src/com/android/inputmethod/latin/Utils.java | 34 -------------------- 4 files changed, 42 insertions(+), 42 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 602de9203..4772334ce 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -2323,7 +2323,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // update keypress sound volume private void updateSoundEffectVolume() { - mFxVolume = Utils.getCurrentKeypressSoundVolume(mPrefs, mResources); + mFxVolume = SettingsValues.getCurrentKeypressSoundVolume(mPrefs, mResources); } // update flags for silent mode @@ -2336,7 +2336,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } private void updateKeypressVibrationDuration() { - mKeypressVibrationDuration = Utils.getCurrentVibrationDuration(mPrefs, mResources); + mKeypressVibrationDuration = SettingsValues.getCurrentVibrationDuration(mPrefs, mResources); } private void playKeyClick(int primaryCode) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 27003280c..31c92e363 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -447,7 +447,7 @@ public class Settings extends InputMethodSettingsActivity SharedPreferences sp, Resources res) { if (mKeypressVibrationDurationSettingsPref != null) { mKeypressVibrationDurationSettingsPref.setSummary( - Utils.getCurrentVibrationDuration(sp, res) + SettingsValues.getCurrentVibrationDuration(sp, res) + res.getString(R.string.settings_ms)); } } @@ -475,7 +475,7 @@ public class Settings extends InputMethodSettingsActivity }); final View v = context.getLayoutInflater().inflate( R.layout.vibration_settings_dialog, null); - final int currentMs = Utils.getCurrentVibrationDuration( + final int currentMs = SettingsValues.getCurrentVibrationDuration( getPreferenceManager().getSharedPreferences(), getResources()); mKeypressVibrationDurationSettingsTextView = (TextView)v.findViewById(R.id.vibration_value); final SeekBar sb = (SeekBar)v.findViewById(R.id.vibration_settings); @@ -504,8 +504,8 @@ public class Settings extends InputMethodSettingsActivity private void updateKeypressSoundVolumeSummary(SharedPreferences sp, Resources res) { if (mKeypressSoundVolumeSettingsPref != null) { - mKeypressSoundVolumeSettingsPref.setSummary( - String.valueOf((int)(Utils.getCurrentKeypressSoundVolume(sp, res) * 100))); + mKeypressSoundVolumeSettingsPref.setSummary(String.valueOf( + (int)(SettingsValues.getCurrentKeypressSoundVolume(sp, res) * 100))); } } @@ -534,7 +534,7 @@ public class Settings extends InputMethodSettingsActivity }); final View v = context.getLayoutInflater().inflate( R.layout.sound_effect_volume_dialog, null); - final int currentVolumeInt = (int)(Utils.getCurrentKeypressSoundVolume( + final int currentVolumeInt = (int)(SettingsValues.getCurrentKeypressSoundVolume( getPreferenceManager().getSharedPreferences(), getResources()) * 100); mKeypressSoundVolumeSettingsTextView = (TextView)v.findViewById(R.id.sound_effect_volume_value); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 4aa683abe..50fa69401 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -19,11 +19,13 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; +import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; +import com.android.inputmethod.latin.R.array; import java.util.Arrays; import java.util.Locale; @@ -241,4 +243,36 @@ public class SettingsValues { public boolean isVoiceKeyOnMain() { return mVoiceKeyOnMain; } -} \ No newline at end of file + + public static float getCurrentKeypressSoundVolume(SharedPreferences sp, Resources res) { + final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); + if (volume >= 0) { + return volume; + } + + final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : volumePerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1.0f; + } + + public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) { + final int ms = sp.getInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, -1); + if (ms >= 0) { + return ms; + } + final String[] durationPerHardwareList = res.getStringArray( + R.array.keypress_vibration_durations); + final String hardwarePrefix = Build.HARDWARE + ","; + for (final String element : durationPerHardwareList) { + if (element.startsWith(hardwarePrefix)) { + return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); + } + } + return -1; + } +} diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 3d0aa09f1..7f507fe02 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -17,11 +17,9 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.content.SharedPreferences; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.os.AsyncTask; -import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -778,38 +776,6 @@ public class Utils { return s.toUpperCase(locale).charAt(0) + s.substring(1); } - public static int getCurrentVibrationDuration(SharedPreferences sp, Resources res) { - final int ms = sp.getInt(Settings.PREF_KEYPRESS_VIBRATION_DURATION_SETTINGS, -1); - if (ms >= 0) { - return ms; - } - final String[] durationPerHardwareList = res.getStringArray( - R.array.keypress_vibration_durations); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : durationPerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1; - } - - public static float getCurrentKeypressSoundVolume(SharedPreferences sp, Resources res) { - final float volume = sp.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, -1.0f); - if (volume >= 0) { - return volume; - } - - final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : volumePerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1.0f; - } - public static boolean willAutoCorrect(SuggestedWords suggestions) { return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate && !suggestions.shouldBlockAutoCorrection(); -- cgit v1.2.3-83-g751a From a8b6292ceeae5fe034e45765d70956aabbf7e07a Mon Sep 17 00:00:00 2001 From: satok Date: Thu, 8 Dec 2011 12:43:40 +0900 Subject: Add a functionality to attach a log file to Gmail app Bug: 5722703 Change-Id: I089f944bdbf2cbb036eb59dd9b5b414370c770f1 --- java/src/com/android/inputmethod/latin/Utils.java | 112 ++++++++++++++++------ 1 file changed, 85 insertions(+), 27 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 7f507fe02..82f27558f 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -16,10 +16,21 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; +import com.android.inputmethod.compat.InputTypeCompatUtils; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardId; + import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; +import android.net.Uri; import android.os.AsyncTask; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -29,20 +40,15 @@ import android.text.format.DateUtils; import android.util.Log; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardId; - import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; +import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; @@ -502,32 +508,84 @@ public class Utils { }); } - public void printAll() { + private synchronized String getBufferedLogs() { + mWriter.flush(); + StringBuilder sb = new StringBuilder(); + BufferedReader br = getBufferedReader(); + String line; + try { + while ((line = br.readLine()) != null) { + sb.append('\n'); + sb.append(line); + } + } catch (IOException e) { + Log.e(USABILITY_TAG, "Can't read log file."); + } finally { + if (LatinImeLogger.sDBG) { + Log.d(USABILITY_TAG, "Got all buffered logs\n" + sb.toString()); + } + try { + br.close(); + } catch (IOException e) { + // ignore. + } + } + return sb.toString(); + } + + public void emailResearcherLogsAll() { mLoggingHandler.post(new Runnable() { @Override public void run() { + if (mFile == null) { + Log.w(TAG, "No internal log file found."); + return; + } + if (mIms.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_EXTERNAL_STORAGE) + != PackageManager.PERMISSION_GRANTED) { + Log.w(TAG, "Doesn't have the permission WRITE_EXTERNAL_STORAGE"); + return; + } mWriter.flush(); - StringBuilder sb = new StringBuilder(); - BufferedReader br = getBufferedReader(); - String line; + final String destPath = + Environment.getExternalStorageDirectory() + "/" + FILENAME; + final File destFile = new File(destPath); try { - while ((line = br.readLine()) != null) { - sb.append('\n'); - sb.append(line); - } - } catch (IOException e) { - Log.e(USABILITY_TAG, "Can't read log file."); - } finally { - if (LatinImeLogger.sDBG) { - Log.d(USABILITY_TAG, "output all logs\n" + sb.toString()); - } - mIms.getCurrentInputConnection().commitText(sb.toString(), 0); - try { - br.close(); - } catch (IOException e) { - // ignore. - } + final FileChannel src = (new FileInputStream(mFile)).getChannel(); + final FileChannel dest = (new FileOutputStream(destFile)).getChannel(); + src.transferTo(0, src.size(), dest); + src.close(); + dest.close(); + } catch (FileNotFoundException e1) { + Log.w(TAG, e1); + return; + } catch (IOException e2) { + Log.w(TAG, e2); + return; + } + if (destFile == null || !destFile.exists()) { + Log.w(TAG, "Dest file doesn't exist."); + return; } + final Intent intent = new Intent(Intent.ACTION_SEND); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + if (LatinImeLogger.sDBG) { + Log.d(TAG, "Destination file URI is " + destFile.toURI()); + } + intent.setType("text/plain"); + intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath)); + intent.putExtra(Intent.EXTRA_SUBJECT, "[Research Logs]"); + mIms.startActivity(intent); + } + }); + } + + public void printAll() { + mLoggingHandler.post(new Runnable() { + @Override + public void run() { + mIms.getCurrentInputConnection().commitText(getBufferedLogs(), 0); } }); } -- cgit v1.2.3-83-g751a From 2edd109f84cb85091b7cf81ec5c6be92bde129cb Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Sat, 10 Dec 2011 00:35:50 +0900 Subject: Some tweaks for Researcher Mode Change-Id: I6b16dd2fe6d7356c747ba0ee2da5976738003ded --- java/src/com/android/inputmethod/latin/LatinImeLogger.java | 2 +- java/src/com/android/inputmethod/latin/Settings.java | 1 + java/src/com/android/inputmethod/latin/Utils.java | 11 ++++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 9903209dd..2041acadf 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -33,7 +33,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { } - public static void init(Context context, SharedPreferences prefs) { + public static void init(LatinIME context, SharedPreferences prefs) { } public static void commit() { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index ac4f705ea..87ac464f8 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -237,6 +237,7 @@ public class Settings extends InputMethodSettingsActivity textCorrectionGroup.removePreference(dictionaryLink); } + // TODO: Following isResearcherPackage can be wrong until LatinImeLogger gets initialized. final boolean isResearcherPackage = LatinImeLogger.isResearcherPackage(); final boolean showUsabilityStudyModeOption = res.getBoolean(R.bool.config_enable_usability_study_mode_option) diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 82f27558f..75bc10cf3 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -537,6 +537,10 @@ public class Utils { mLoggingHandler.post(new Runnable() { @Override public void run() { + final Date date = new Date(); + date.setTime(System.currentTimeMillis()); + final String currentDateTimeString = + new SimpleDateFormat("yyyyMMdd-HHmmssZ").format(date); if (mFile == null) { Log.w(TAG, "No internal log file found."); return; @@ -548,8 +552,8 @@ public class Utils { return; } mWriter.flush(); - final String destPath = - Environment.getExternalStorageDirectory() + "/" + FILENAME; + final String destPath = Environment.getExternalStorageDirectory() + + "/research-" + currentDateTimeString + ".log"; final File destFile = new File(destPath); try { final FileChannel src = (new FileInputStream(mFile)).getChannel(); @@ -575,7 +579,8 @@ public class Utils { } intent.setType("text/plain"); intent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + destPath)); - intent.putExtra(Intent.EXTRA_SUBJECT, "[Research Logs]"); + intent.putExtra(Intent.EXTRA_SUBJECT, + "[Research Logs] " + currentDateTimeString); mIms.startActivity(intent); } }); -- cgit v1.2.3-83-g751a From 406d192a9e8f07ed6c6a408650feb0a757ca388e Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Mon, 12 Dec 2011 16:22:07 +0900 Subject: Remove side-effects from TextEntryState Change-Id: Ib98eea9e791e426435cfdfd0c9ab3ed9061664aa --- .../com/android/inputmethod/latin/LatinIME.java | 19 +++++++++++++++-- .../android/inputmethod/latin/TextEntryState.java | 10 --------- java/src/com/android/inputmethod/latin/Utils.java | 24 ++++++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 4d60976ea..95fdcc176 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1433,6 +1433,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // TODO: Merge space state with TextEntryState TextEntryState.backspace(); if (null != mWordSavedForAutoCorrectCancellation) { + Utils.Stats.onAutoCorrectionCancellation(); cancelAutoCorrect(ic); mWordSavedForAutoCorrectCancellation = null; ic.endBatchEdit(); @@ -1576,7 +1577,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } switcher.updateShiftState(); - TextEntryState.typedCharacter((char) code, mSettingsValues.isWordSeparator(code), x, y); + if (mSettingsValues.isWordSeparator(code)) { + TextEntryState.typedCharacter((char) code, true, x, y); + Utils.Stats.onSeparator((char)code, x, y); + } else { + TextEntryState.typedCharacter((char) code, false, x, y); + Utils.Stats.onNonSeparator((char)code, x, y); + } if (null != ic) ic.endBatchEdit(); } @@ -1659,6 +1666,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } TextEntryState.typedCharacter((char) primaryCode, true, x, y); + Utils.Stats.onSeparator((char)primaryCode, x, y); if (pickedDefault) { CharSequence typedWord = mWordComposer.getTypedWord(); @@ -1870,7 +1878,10 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar updateSuggestions(); } if (mBestWord != null && mBestWord.length() > 0) { - TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, separatorCode); + Utils.Stats.onAutoCorrection(mWordComposer.getTypedWord(), mBestWord.toString(), + separatorCode); + TextEntryState.acceptedDefault(mWordComposer.getTypedWord(), mBestWord, + separatorCode); mExpectingUpdateSelection = true; commitBestWord(mBestWord); if (!mBestWord.equals(mWordComposer.getTypedWord())) { @@ -1979,6 +1990,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // TextEntryState.State.PICKED_SUGGESTION state. TextEntryState.typedCharacter((char) Keyboard.CODE_SPACE, true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + Utils.Stats.onSeparator((char)Keyboard.CODE_SPACE, WordComposer.NOT_A_COORDINATE, + WordComposer.NOT_A_COORDINATE); if (!showingAddToDictionaryHint) { // If we're not showing the "Touch again to save", then show corrections again. // In case the cursor position doesn't change, make sure we show the suggestions again. @@ -2199,6 +2212,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(separator, 1); TextEntryState.typedCharacter(separator.charAt(0), true, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, + WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); mHandler.postUpdateSuggestions(); } diff --git a/java/src/com/android/inputmethod/latin/TextEntryState.java b/java/src/com/android/inputmethod/latin/TextEntryState.java index 6b44fc500..ebaecf7fd 100644 --- a/java/src/com/android/inputmethod/latin/TextEntryState.java +++ b/java/src/com/android/inputmethod/latin/TextEntryState.java @@ -17,7 +17,6 @@ package com.android.inputmethod.latin; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.Utils.RingCharBuffer; import android.text.TextUtils; import android.util.Log; @@ -48,8 +47,6 @@ public class TextEntryState { int separatorCode) { if (TextUtils.isEmpty(typedWord)) return; setState(ACCEPTED_DEFAULT); - LatinImeLogger.logOnAutoCorrection( - typedWord.toString(), actualWord.toString(), separatorCode); if (DEBUG) displayState("acceptedDefault", "typedWord", typedWord, "actualWord", actualWord); } @@ -131,19 +128,12 @@ public class TextEntryState { } break; } - RingCharBuffer.getInstance().push(c, x, y); - if (isSeparator) { - LatinImeLogger.logOnInputSeparator(); - } else { - LatinImeLogger.logOnInputChar(); - } if (DEBUG) displayState("typedCharacter", "char", c, "isSeparator", isSeparator); } public static void backspace() { if (sState == ACCEPTED_DEFAULT) { setState(UNDO_COMMIT); - LatinImeLogger.logOnAutoCorrectionCancelled(); } else if (sState == UNDO_COMMIT) { setState(IN_WORD); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 75bc10cf3..de29e8f74 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -843,4 +843,28 @@ public class Utils { return !suggestions.mTypedWordValid && suggestions.mHasAutoCorrectionCandidate && !suggestions.shouldBlockAutoCorrection(); } + + public static class Stats { + public static void onNonSeparator(final char code, final int x, + final int y) { + RingCharBuffer.getInstance().push(code, x, y); + LatinImeLogger.logOnInputChar(); + } + + public static void onSeparator(final char code, final int x, + final int y) { + RingCharBuffer.getInstance().push(code, x, y); + LatinImeLogger.logOnInputSeparator(); + } + + public static void onAutoCorrection(final String typedWord, final String correctedWord, + final int separatorCode) { + if (TextUtils.isEmpty(typedWord)) return; + LatinImeLogger.logOnAutoCorrection(typedWord, correctedWord, separatorCode); + } + + public static void onAutoCorrectionCancellation() { + LatinImeLogger.logOnAutoCorrectionCancelled(); + } + } } -- cgit v1.2.3-83-g751a From ba526e3157e04cbfa5a6183ec14a5d01dd3c9b10 Mon Sep 17 00:00:00 2001 From: satok Date: Tue, 13 Dec 2011 17:21:37 +0900 Subject: Extract the jni library name Change-Id: Icc58ccea1178d9f35f5be0dceebab67bbb965b7f --- java/src/com/android/inputmethod/latin/Utils.java | 9 +++++++-- .../inputmethod/latin/define/JniLibName.java | 21 +++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/define/JniLibName.java (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index de29e8f74..64f4d058b 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -22,6 +22,7 @@ import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.latin.define.JniLibName; import android.content.Context; import android.content.Intent; @@ -691,9 +692,13 @@ public class Utils { public static void loadNativeLibrary() { try { - System.loadLibrary("jni_latinime"); + System.loadLibrary(JniLibName.JNI_LIB_NAME); } catch (UnsatisfiedLinkError ule) { - Log.e(TAG, "Could not load native library jni_latinime"); + Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME); + if (LatinImeLogger.sDBG) { + throw new RuntimeException( + "Could not load native library " + JniLibName.JNI_LIB_NAME); + } } } diff --git a/java/src/com/android/inputmethod/latin/define/JniLibName.java b/java/src/com/android/inputmethod/latin/define/JniLibName.java new file mode 100644 index 000000000..3e94a3c07 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/define/JniLibName.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2011 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.define; + +public class JniLibName { + public static final String JNI_LIB_NAME = "jni_latinime"; +} -- cgit v1.2.3-83-g751a From 23d27fefcbfe04df8f8762d5d50117a58fb011e9 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 15 Dec 2011 16:09:42 +0900 Subject: Fix auto correction spacebar LED Change-Id: I4894d188d5612380cc9f8eec7cb72544e37fb2b0 --- java/res/values/config.xml | 1 - java/res/values/styles.xml | 4 +- .../inputmethod/keyboard/KeyboardSwitcher.java | 41 +++++++++++------ .../inputmethod/keyboard/LatinKeyboard.java | 53 +++++++++++----------- .../inputmethod/keyboard/LatinKeyboardView.java | 9 ---- .../com/android/inputmethod/latin/LatinIME.java | 37 +++++++++------ .../android/inputmethod/latin/SubtypeSwitcher.java | 7 +-- java/src/com/android/inputmethod/latin/Utils.java | 3 +- 8 files changed, 82 insertions(+), 73 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/values/config.xml b/java/res/values/config.xml index bad4bc625..8b99a1fcb 100644 --- a/java/res/values/config.xml +++ b/java/res/values/config.xml @@ -38,7 +38,6 @@ false false true - false false diff --git a/java/res/values/styles.xml b/java/res/values/styles.xml index 43aa58388..2b5fb08e5 100644 --- a/java/res/values/styles.xml +++ b/java/res/values/styles.xml @@ -32,8 +32,7 @@ @integer/config_max_more_keys_column @@ -242,6 +241,7 @@ name="LatinKeyboard.IceCreamSandwich" parent="LatinKeyboard" > + false @drawable/sym_keyboard_voice_off_holo diff --git a/java/res/values/keyboard-icons-ics.xml b/java/res/values/keyboard-icons-ics.xml index f68be5f1e..5fba0253d 100644 --- a/java/res/values/keyboard-icons-ics.xml +++ b/java/res/values/keyboard-icons-ics.xml @@ -33,5 +33,6 @@ @drawable/sym_keyboard_shift_locked_holo @drawable/sym_keyboard_voice_off_holo @drawable/sym_keyboard_feedback_tab + @drawable/sym_keyboard_language_switch diff --git a/java/res/values/keyboard-icons-white.xml b/java/res/values/keyboard-icons-white.xml index 35197a1c0..837b1a37a 100644 --- a/java/res/values/keyboard-icons-white.xml +++ b/java/res/values/keyboard-icons-white.xml @@ -31,5 +31,6 @@ @drawable/sym_keyboard_voice_off_holo @drawable/sym_keyboard_feedback_tab + @drawable/sym_keyboard_language_switch diff --git a/java/res/values/keycodes.xml b/java/res/values/keycodes.xml index 7f9e4bda4..d3d9b6324 100644 --- a/java/res/values/keycodes.xml +++ b/java/res/values/keycodes.xml @@ -32,5 +32,6 @@ -7 -8 -9 - -10 + -10 + -11 diff --git a/java/res/values/strings.xml b/java/res/values/strings.xml index d8a3a689e..f2c02d014 100644 --- a/java/res/values/strings.xml +++ b/java/res/values/strings.xml @@ -64,6 +64,13 @@ Options for experts + + Switch to other input methods + + Language switch key covers other input methods too + + Suppress language switch key + Key popup dismiss delay diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml index 76eacb673..f153a7d96 100644 --- a/java/res/xml/key_styles_common.xml +++ b/java/res/xml/key_styles_common.xml @@ -117,10 +117,10 @@ latin:altCode="@integer/key_space" latin:parentStyle="f1MoreKeysStyle" /> + + - + + + + + + + + + + getEnabledInputMethodSubtypeList( InputMethodInfoCompatWrapper imi, boolean allowsImplicitlySelectedSubtypes) { if (!SUBTYPE_SUPPORTED) { @@ -221,6 +234,14 @@ public class InputMethodManagerCompatWrapper { return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToLastInputMethod, token); } + public boolean switchToNextInputMethod(IBinder token, boolean onlyCurrentIme) { + if (SubtypeSwitcher.getInstance().isDummyVoiceMode()) { + return true; + } + return (Boolean)CompatUtils.invoke(mImm, false, METHOD_switchToNextInputMethod, token, + onlyCurrentIme); + } + public List getEnabledInputMethodList() { if (mImm == null) return null; List imis = new ArrayList(); diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index c6cdf7986..5660d1942 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -99,8 +99,9 @@ public class Keyboard { public static final int CODE_ACTION_ENTER = -7; public static final int CODE_ACTION_NEXT = -8; public static final int CODE_ACTION_PREVIOUS = -9; + public static final int CODE_LANGUAGE_SWITCH = -10; // Code value representing the code is not specified. - public static final int CODE_UNSPECIFIED = -10; + public static final int CODE_UNSPECIFIED = -11; public final KeyboardId mId; public final int mThemeId; @@ -1076,6 +1077,9 @@ public class Keyboard { R.styleable.Keyboard_Case_shortcutKeyEnabled, id.mShortcutKeyEnabled); final boolean hasShortcutKeyMatched = matchBoolean(a, R.styleable.Keyboard_Case_hasShortcutKey, id.mHasShortcutKey); + final boolean languageSwitchKeyEnabledMatched = matchBoolean(a, + R.styleable.Keyboard_Case_languageSwitchKeyEnabled, + id.mLanguageSwitchKeyEnabled); final boolean isMultiLineMatched = matchBoolean(a, R.styleable.Keyboard_Case_isMultiLine, id.isMultiLine()); final boolean imeActionMatched = matchInteger(a, @@ -1089,11 +1093,12 @@ public class Keyboard { final boolean selected = keyboardSetElementMatched && modeMatched && navigateNextMatched && navigatePreviousMatched && passwordInputMatched && clobberSettingsKeyMatched && shortcutKeyEnabledMatched - && hasShortcutKeyMatched && isMultiLineMatched && imeActionMatched - && localeCodeMatched && languageCodeMatched && countryCodeMatched; + && hasShortcutKeyMatched && languageSwitchKeyEnabledMatched + && isMultiLineMatched && imeActionMatched && localeCodeMatched + && languageCodeMatched && countryCodeMatched; if (DEBUG) { - startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, + startTag("<%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s>%s", TAG_CASE, textAttr(a.getString(R.styleable.Keyboard_Case_keyboardSetElement), "keyboardSetElement"), textAttr(a.getString(R.styleable.Keyboard_Case_mode), "mode"), @@ -1111,6 +1116,8 @@ public class Keyboard { "shortcutKeyEnabled"), booleanAttr(a, R.styleable.Keyboard_Case_hasShortcutKey, "hasShortcutKey"), + booleanAttr(a, R.styleable.Keyboard_Case_languageSwitchKeyEnabled, + "languageSwitchKeyEnabled"), booleanAttr(a, R.styleable.Keyboard_Case_isMultiLine, "isMultiLine"), textAttr(a.getString(R.styleable.Keyboard_Case_localeCode), diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java index f5752962e..6703b9301 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java @@ -62,13 +62,14 @@ public class KeyboardId { public final boolean mClobberSettingsKey; public final boolean mShortcutKeyEnabled; public final boolean mHasShortcutKey; + public final boolean mLanguageSwitchKeyEnabled; public final String mCustomActionLabel; private final int mHashCode; public KeyboardId(int elementId, Locale locale, int orientation, int width, int mode, EditorInfo editorInfo, boolean clobberSettingsKey, boolean shortcutKeyEnabled, - boolean hasShortcutKey) { + boolean hasShortcutKey, boolean languageSwitchKeyEnabled) { this.mLocale = locale; this.mOrientation = orientation; this.mWidth = width; @@ -78,6 +79,7 @@ public class KeyboardId { this.mClobberSettingsKey = clobberSettingsKey; this.mShortcutKeyEnabled = shortcutKeyEnabled; this.mHasShortcutKey = hasShortcutKey; + this.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; this.mCustomActionLabel = (editorInfo.actionLabel != null) ? editorInfo.actionLabel.toString() : null; @@ -94,6 +96,7 @@ public class KeyboardId { id.mClobberSettingsKey, id.mShortcutKeyEnabled, id.mHasShortcutKey, + id.mLanguageSwitchKeyEnabled, id.isMultiLine(), id.imeAction(), id.mCustomActionLabel, @@ -114,6 +117,7 @@ public class KeyboardId { && other.mClobberSettingsKey == this.mClobberSettingsKey && other.mShortcutKeyEnabled == this.mShortcutKeyEnabled && other.mHasShortcutKey == this.mHasShortcutKey + && other.mLanguageSwitchKeyEnabled == this.mLanguageSwitchKeyEnabled && other.isMultiLine() == this.isMultiLine() && other.imeAction() == this.imeAction() && TextUtils.equals(other.mCustomActionLabel, this.mCustomActionLabel) @@ -172,7 +176,7 @@ public class KeyboardId { @Override public String toString() { - return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s]", + return String.format("[%s %s %s%d %s %s %s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mLocale, (mOrientation == 1 ? "port" : "land"), mWidth, @@ -184,6 +188,7 @@ public class KeyboardId { (passwordInput() ? " passwordInput" : ""), (mShortcutKeyEnabled ? " shortcutKeyEnabled" : ""), (mHasShortcutKey ? " hasShortcutKey" : ""), + (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), (isMultiLine() ? "isMultiLine" : "") ); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index ee882edc0..731aaf7c5 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -101,6 +101,7 @@ public class KeyboardSet { boolean mVoiceKeyEnabled; boolean mVoiceKeyOnMain; boolean mNoSettingsKey; + boolean mLanguageSwitchKeyEnabled; Locale mLocale; int mOrientation; int mWidth; @@ -196,7 +197,7 @@ public class KeyboardSet { && (isSymbols != params.mVoiceKeyOnMain); return new KeyboardId(keyboardSetElementId, params.mLocale, params.mOrientation, params.mWidth, params.mMode, params.mEditorInfo, params.mNoSettingsKey, - params.mVoiceKeyEnabled, hasShortcutKey); + params.mVoiceKeyEnabled, hasShortcutKey, params.mLanguageSwitchKeyEnabled); } public static class Builder { @@ -239,7 +240,8 @@ public class KeyboardSet { return this; } - public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain) { + public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, + boolean languageSwitchKeyEnabled) { @SuppressWarnings("deprecation") final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions( null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); @@ -248,6 +250,7 @@ public class KeyboardSet { || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; mParams.mVoiceKeyOnMain = voiceKeyOnMain; + mParams.mLanguageSwitchKeyEnabled = languageSwitchKeyEnabled; return this; } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index e1c6f2604..ac8dd1b95 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -133,7 +133,8 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION)); builder.setOptions( settingsValues.isVoiceKeyEnabled(editorInfo), - settingsValues.isVoiceKeyOnMain()); + settingsValues.isVoiceKeyOnMain(), + settingsValues.isLanguageSwitchKeyEnabled(mThemeContext)); mKeyboardSet = builder.build(); try { mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols)); diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index 78c371ff0..afc4932e9 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -489,7 +489,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode); return true; } - if (primaryCode == Keyboard.CODE_SPACE) { + if (primaryCode == Keyboard.CODE_SPACE || primaryCode == Keyboard.CODE_LANGUAGE_SWITCH) { // Long pressing the space key invokes IME switcher dialog. if (invokeCustomRequest(LatinIME.CODE_SHOW_INPUT_METHOD_PICKER)) { tracker.onLongPressed(); @@ -782,6 +782,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { drawKeyPopupHint(key, canvas, paint, params); } + } else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) { + super.onDrawKeyTopVisuals(key, canvas, paint, params); + if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + drawKeyPopupHint(key, canvas, paint, params); + } } else { super.onDrawKeyTopVisuals(key, canvas, paint, params); } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 7c8fd1225..ca711ec7d 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -31,7 +31,7 @@ public class KeyboardIconsSet { // The value should be aligned with the enum value of Key.keyIcon. public static final int ICON_UNDEFINED = 0; - private static final int NUM_ICONS = 13; + private static final int NUM_ICONS = 14; private final Drawable[] mIcons = new Drawable[NUM_ICONS + 1]; @@ -57,6 +57,7 @@ public class KeyboardIconsSet { addIconIdMap(11, "shiftKeyShifted", R.styleable.Keyboard_iconShiftKeyShifted); addIconIdMap(12, "disabledShortcurKey", R.styleable.Keyboard_iconDisabledShortcutKey); addIconIdMap(13, "previewTabKey", R.styleable.Keyboard_iconPreviewTabKey); + addIconIdMap(14, "languageSwitchKey", R.styleable.Keyboard_iconLanguageSwitchKey); } private static void addIconIdMap(int iconId, String name, int attrId) { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2bcd947f1..cb22b4935 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -29,6 +29,7 @@ import android.inputmethodservice.InputMethodService; import android.media.AudioManager; import android.net.ConnectivityManager; import android.os.Debug; +import android.os.IBinder; import android.os.Message; import android.os.SystemClock; import android.preference.PreferenceActivity; @@ -55,6 +56,7 @@ import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; @@ -196,6 +198,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private KeyboardSwitcher mKeyboardSwitcher; private SubtypeSwitcher mSubtypeSwitcher; private VoiceProxy mVoiceProxy; + private boolean mShouldSwitchToLastSubtype = true; private UserDictionary mUserDictionary; private UserBigramDictionary mUserBigramDictionary; @@ -1263,6 +1266,25 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } + private void handleLanguageSwitchKey() { + final boolean includesOtherImes = !mSettingsValues.mIncludesOtherImesInLanguageSwitchList; + final IBinder token = getWindow().getWindow().getAttributes().token; + if (mShouldSwitchToLastSubtype) { + final InputMethodSubtypeCompatWrapper lastSubtype = mImm.getLastInputMethodSubtype(); + final boolean lastSubtypeBelongsToThisIme = Utils.checkIfSubtypeBelongsToThisIme( + this, lastSubtype); + if ((includesOtherImes || lastSubtypeBelongsToThisIme) + && mImm.switchToLastInputMethod(token)) { + mShouldSwitchToLastSubtype = false; + } else { + mImm.switchToNextInputMethod(token, !includesOtherImes); + mShouldSwitchToLastSubtype = true; + } + } else { + mImm.switchToNextInputMethod(token, !includesOtherImes); + } + } + private void sendKeyCodePoint(int code) { // TODO: Remove this special handling of digit letters. // For backward compatibility. See {@link InputMethodService#sendKeyChar(char)}. @@ -1306,6 +1328,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleBackspace(spaceState); mDeleteCount++; mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; LatinImeLogger.logOnDelete(); break; case Keyboard.CODE_SHIFT: @@ -1327,6 +1350,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar case Keyboard.CODE_ACTION_PREVIOUS: EditorInfoCompatUtils.performEditorActionPrevious(getCurrentInputConnection()); break; + case Keyboard.CODE_LANGUAGE_SWITCH: + handleLanguageSwitchKey(); + break; default: mSpaceState = SPACE_STATE_NONE; if (mSettingsValues.isWordSeparator(primaryCode)) { @@ -1335,6 +1361,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar handleCharacter(primaryCode, x, y, spaceState); } mExpectingUpdateSelection = true; + mShouldSwitchToLastSubtype = true; break; } switcher.onCodeInput(primaryCode); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 3029057be..305cef22d 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -43,7 +43,6 @@ import android.widget.SeekBar.OnSeekBarChangeListener; import android.widget.TextView; import com.android.inputmethod.compat.CompatUtils; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatWrapper; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.deprecated.VoiceProxy; @@ -73,6 +72,10 @@ public class Settings extends InputMethodSettingsActivity public static final String PREF_MISC_SETTINGS = "misc_settings"; public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; + public static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = + "pref_suppress_language_switch_key"; + public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST = + "pref_include_other_imes_in_language_switch_list"; public static final String PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY = "pref_key_preview_popup_dismiss_delay"; public static final String PREF_KEY_USE_CONTACTS_DICT = "pref_key_use_contacts_dict"; @@ -204,6 +207,11 @@ public class Settings extends InputMethodSettingsActivity } } + final CheckBoxPreference includeOtherImesInLanguageSwitchList = + (CheckBoxPreference)findPreference(PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); + includeOtherImesInLanguageSwitchList.setEnabled( + !SettingsValues.isLanguageSwitchKeySupressed(prefs)); + mKeyPreviewPopupDismissDelay = (ListPreference)findPreference(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY); final String[] entries = new String[] { @@ -316,6 +324,12 @@ public class Settings extends InputMethodSettingsActivity if (null != popupDismissDelay) { popupDismissDelay.setEnabled(prefs.getBoolean(PREF_POPUP_ON, true)); } + } else if (key.equals(PREF_SUPPRESS_LANGUAGE_SWITCH_KEY)) { + final CheckBoxPreference includeOtherImesInLanguageSwicthList = + (CheckBoxPreference)findPreference( + PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST); + includeOtherImesInLanguageSwicthList.setEnabled( + !SettingsValues.isLanguageSwitchKeySupressed(prefs)); } ensureConsistencyOfAutoCorrectionSettings(); mVoiceOn = !(prefs.getString(PREF_VOICE_MODE, mVoiceModeOff) diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 6d65a74c8..69e45f619 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -23,11 +23,14 @@ import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; +import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.compat.VibratorCompatWrapper; import com.android.inputmethod.keyboard.internal.KeySpecParser; import java.util.Arrays; +import java.util.Collections; +import java.util.List; import java.util.Locale; public class SettingsValues { @@ -55,6 +58,8 @@ public class SettingsValues { public final String mShowSuggestionsSetting; @SuppressWarnings("unused") // TODO: Use this private final boolean mUsabilityStudyMode; + public final boolean mIncludesOtherImesInLanguageSwitchList; + public final boolean mIsLanguageSwitchKeySuppressed; @SuppressWarnings("unused") // TODO: Use this private final String mKeyPreviewPopupDismissDelayRawValue; public final boolean mUseContactsDict; @@ -127,6 +132,9 @@ public class SettingsValues { mShowSuggestionsSetting = prefs.getString(Settings.PREF_SHOW_SUGGESTIONS_SETTING, res.getString(R.string.prefs_suggestion_visibility_default_value)); mUsabilityStudyMode = getUsabilityStudyMode(prefs); + mIncludesOtherImesInLanguageSwitchList = prefs.getBoolean( + Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false); + mIsLanguageSwitchKeySuppressed = isLanguageSwitchKeySupressed(prefs); mKeyPreviewPopupDismissDelayRawValue = prefs.getString( Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); @@ -309,6 +317,22 @@ public class SettingsValues { return mVoiceKeyOnMain; } + public static boolean isLanguageSwitchKeySupressed(SharedPreferences sp) { + return sp.getBoolean(Settings.PREF_SUPPRESS_LANGUAGE_SWITCH_KEY, false); + } + + public boolean isLanguageSwitchKeyEnabled(Context context) { + if (mIsLanguageSwitchKeySuppressed) { + return false; + } + if (mIncludesOtherImesInLanguageSwitchList) { + return Utils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false); + } else { + return Utils.hasMultipleEnabledSubtypesInThisIme( + context, /* include aux subtypes */false); + } + } + public boolean isFullscreenModeAllowed(Resources res) { return res.getBoolean(R.bool.config_use_fullscreen_mode); } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 33d4b877e..a8679e07a 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -52,6 +52,7 @@ import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; @@ -117,16 +118,51 @@ public class Utils { } } + // TODO: Move InputMethodSubtype related utility methods to its own utility class. + // TODO: Cache my InputMethodInfo and/or InputMethodSubtype list. + public static boolean checkIfSubtypeBelongsToThisIme(Context context, + InputMethodSubtypeCompatWrapper ims) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; + + final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( + context.getPackageName()); + final List subtypes = + imm.getEnabledInputMethodSubtypeList(myImi, true); + for (final InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (subtype.equals(ims)) { + return true; + } + } + return false; + } + public static boolean hasMultipleEnabledIMEsOrSubtypes( final boolean shouldIncludeAuxiliarySubtypes) { final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); if (imm == null) return false; + final List enabledImis = imm.getEnabledInputMethodList(); + return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); + } + + public static boolean hasMultipleEnabledSubtypesInThisIme(Context context, + final boolean shouldIncludeAuxiliarySubtypes) { + final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( + context.getPackageName()); + final List imiList = Collections.singletonList(myImi); + return Utils.hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); + } + + private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, + List imiList) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; // Number of the filtered IMEs int filteredImisCount = 0; - for (InputMethodInfoCompatWrapper imi : enabledImis) { + for (InputMethodInfoCompatWrapper imi : imiList) { // We can return true immediately after we find two or more filtered IMEs. if (filteredImisCount > 1) return true; final List subtypes = @@ -564,6 +600,7 @@ public class Utils { } } + // TODO: Move this method to KeyboardSet class. public static int getKeyboardMode(EditorInfo editorInfo) { if (editorInfo == null) return KeyboardId.MODE_TEXT; -- cgit v1.2.3-83-g751a From cc8c8b99bd0463f5977dea82f5e2379ea1dd4e73 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Thu, 8 Mar 2012 17:07:02 +0900 Subject: Split Utils class to StringUtils, SubtypeUtils, and JniUtils Change-Id: I09e91675fe7d573dad8c933ad513b21d7e409144 --- .../compat/InputMethodManagerCompatWrapper.java | 7 +- .../android/inputmethod/deprecated/VoiceProxy.java | 6 +- .../languageswitcher/InputLanguageSelection.java | 24 +- .../deprecated/voice/RecognitionView.java | 10 +- java/src/com/android/inputmethod/keyboard/Key.java | 10 +- .../android/inputmethod/keyboard/KeyboardSet.java | 52 ++- .../android/inputmethod/keyboard/KeyboardView.java | 4 +- .../inputmethod/keyboard/LatinKeyboardView.java | 13 +- .../inputmethod/keyboard/MoreKeysKeyboard.java | 4 +- .../inputmethod/keyboard/ProximityInfo.java | 4 +- .../keyboard/internal/KeySpecParser.java | 12 +- .../inputmethod/latin/BinaryDictionary.java | 2 +- .../inputmethod/latin/DictionaryFactory.java | 14 +- .../com/android/inputmethod/latin/JniUtils.java | 41 +++ .../com/android/inputmethod/latin/LatinIME.java | 23 +- .../com/android/inputmethod/latin/Settings.java | 2 +- .../android/inputmethod/latin/SettingsValues.java | 4 +- .../com/android/inputmethod/latin/StringUtils.java | 198 ++++++++++ .../android/inputmethod/latin/SubtypeSwitcher.java | 2 +- .../android/inputmethod/latin/SubtypeUtils.java | 135 +++++++ .../src/com/android/inputmethod/latin/Suggest.java | 50 ++- java/src/com/android/inputmethod/latin/Utils.java | 398 +-------------------- .../spellcheck/AndroidSpellCheckerService.java | 10 +- 23 files changed, 551 insertions(+), 474 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/JniUtils.java create mode 100644 java/src/com/android/inputmethod/latin/StringUtils.java create mode 100644 java/src/com/android/inputmethod/latin/SubtypeUtils.java (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java index 9dd0a599d..bf5f20158 100644 --- a/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java +++ b/java/src/com/android/inputmethod/compat/InputMethodManagerCompatWrapper.java @@ -32,7 +32,7 @@ import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.deprecated.LanguageSwitcherProxy; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.SubtypeUtils; import java.lang.reflect.Method; import java.util.ArrayList; @@ -163,7 +163,7 @@ public class InputMethodManagerCompatWrapper { private InputMethodInfoCompatWrapper getLatinImeInputMethodInfo() { if (TextUtils.isEmpty(mLatinImePackageName)) return null; - return Utils.getInputMethodInfo(mLatinImePackageName); + return SubtypeUtils.getInputMethodInfo(mLatinImePackageName); } private static InputMethodSubtypeCompatWrapper getLastResortSubtype(String mode) { @@ -260,7 +260,8 @@ public class InputMethodManagerCompatWrapper { // The code below are based on {@link InputMethodManager#showInputMethodMenuInternal}. - final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo(mLatinImePackageName); + final InputMethodInfoCompatWrapper myImi = SubtypeUtils.getInputMethodInfo( + mLatinImePackageName); final List myImsList = getEnabledInputMethodSubtypeList( myImi, true); final InputMethodSubtypeCompatWrapper currentIms = getCurrentInputMethodSubtype(); diff --git a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java index c1c6d31cd..87d1c118b 100644 --- a/java/src/com/android/inputmethod/deprecated/VoiceProxy.java +++ b/java/src/com/android/inputmethod/deprecated/VoiceProxy.java @@ -61,8 +61,8 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinIME.UIHandler; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.Utils; import java.util.ArrayList; @@ -662,9 +662,9 @@ public class VoiceProxy implements VoiceInput.UiListener { private boolean shouldShowVoiceButton(FieldContext fieldContext, EditorInfo editorInfo) { @SuppressWarnings("deprecation") - final boolean noMic = Utils.inPrivateImeOptions(null, + final boolean noMic = StringUtils.inPrivateImeOptions(null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo) - || Utils.inPrivateImeOptions(mService.getPackageName(), + || StringUtils.inPrivateImeOptions(mService.getPackageName(), LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo); return ENABLE_VOICE_BUTTON && fieldCanDoVoice(fieldContext) && !noMic && SpeechRecognizer.isRecognitionAvailable(mService); diff --git a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java index e75e14861..421ee6529 100644 --- a/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java +++ b/java/src/com/android/inputmethod/deprecated/languageswitcher/InputLanguageSelection.java @@ -16,16 +16,6 @@ package com.android.inputmethod.deprecated.languageswitcher; -import com.android.inputmethod.compat.SharedPreferencesCompat; -import com.android.inputmethod.keyboard.KeyboardSet; -import com.android.inputmethod.latin.DictionaryFactory; -import com.android.inputmethod.latin.LocaleUtils; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.Settings; -import com.android.inputmethod.latin.Utils; - -import org.xmlpull.v1.XmlPullParserException; - import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.res.Resources; @@ -37,6 +27,16 @@ import android.preference.PreferenceManager; import android.text.TextUtils; import android.util.Pair; +import com.android.inputmethod.compat.SharedPreferencesCompat; +import com.android.inputmethod.keyboard.KeyboardSet; +import com.android.inputmethod.latin.DictionaryFactory; +import com.android.inputmethod.latin.LocaleUtils; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Settings; +import com.android.inputmethod.latin.StringUtils; + +import org.xmlpull.v1.XmlPullParserException; + import java.io.IOException; import java.text.Collator; import java.util.ArrayList; @@ -237,12 +237,12 @@ public class InputLanguageSelection extends PreferenceActivity { if (finalSize == 0) { preprocess[finalSize++] = - new LocaleEntry(Utils.getFullDisplayName(l, false), l); + new LocaleEntry(StringUtils.getFullDisplayName(l, false), l); } else { if (s.equals("zz_ZZ")) { // ignore this locale } else { - final String displayName = Utils.getFullDisplayName(l, false); + final String displayName = StringUtils.getFullDisplayName(l, false); preprocess[finalSize++] = new LocaleEntry(displayName, l); } } diff --git a/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java index 71d15dc3d..ff8b1abce 100644 --- a/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java +++ b/java/src/com/android/inputmethod/deprecated/voice/RecognitionView.java @@ -16,10 +16,6 @@ package com.android.inputmethod.deprecated.voice; -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.SubtypeSwitcher; -import com.android.inputmethod.latin.Utils; - import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -39,6 +35,10 @@ import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeSwitcher; + import java.io.ByteArrayOutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -222,7 +222,7 @@ public class RecognitionView { Locale locale = SubtypeSwitcher.getInstance().getInputLocale(); mLanguage.setVisibility(View.VISIBLE); - mLanguage.setText(Utils.getFullDisplayName(locale, true)); + mLanguage.setText(StringUtils.getFullDisplayName(locale, true)); mPopupLayout.setBackgroundDrawable(mListeningBorder); break; diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java index f3923834b..6b4de184f 100644 --- a/java/src/com/android/inputmethod/keyboard/Key.java +++ b/java/src/com/android/inputmethod/keyboard/Key.java @@ -30,7 +30,7 @@ import com.android.inputmethod.keyboard.internal.KeyStyles; import com.android.inputmethod.keyboard.internal.KeyStyles.KeyStyle; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; @@ -293,7 +293,7 @@ public class Key { // Choose the first letter of the label as primary code if not specified. if (code == Keyboard.CODE_UNSPECIFIED && TextUtils.isEmpty(outputText) && !TextUtils.isEmpty(mLabel)) { - if (Utils.codePointCount(mLabel) == 1) { + if (StringUtils.codePointCount(mLabel) == 1) { // Use the first letter of the hint label if shiftedLetterActivated flag is // specified. if (hasShiftedLetterHint() && isShiftedLetterActivated() @@ -309,7 +309,7 @@ public class Key { mCode = Keyboard.CODE_OUTPUT_TEXT; } } else if (code == Keyboard.CODE_UNSPECIFIED && outputText != null) { - if (Utils.codePointCount(outputText) == 1) { + if (StringUtils.codePointCount(outputText) == 1) { mCode = outputText.codePointAt(0); outputText = null; } else { @@ -336,7 +336,7 @@ public class Key { if (!Keyboard.isLetterCode(code) || preserveCase) return code; final String text = new String(new int[] { code } , 0, 1); final String casedText = adjustCaseOfStringForKeyboardId(text, preserveCase, id); - return Utils.codePointCount(casedText) == 1 + return StringUtils.codePointCount(casedText) == 1 ? casedText.codePointAt(0) : Keyboard.CODE_UNSPECIFIED; } @@ -484,7 +484,7 @@ public class Key { } public int selectTextSize(int letter, int largeLetter, int label, int hintLabel) { - if (Utils.codePointCount(mLabel) > 1 + if (StringUtils.codePointCount(mLabel) > 1 && (mLabelFlags & (LABEL_FLAGS_FOLLOW_KEY_LETTER_RATIO | LABEL_FLAGS_FOLLOW_KEY_HINT_LABEL_RATIO)) == 0) { return label; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index 731aaf7c5..5ac6d03a8 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -21,16 +21,18 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; +import android.text.InputType; import android.util.Log; import android.util.Xml; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.compat.EditorInfoCompatUtils; +import com.android.inputmethod.compat.InputTypeCompatUtils; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.XmlParseUtils; import org.xmlpull.v1.XmlPullParser; @@ -215,9 +217,9 @@ public class KeyboardSet { mEditorInfo = editorInfo; final Params params = mParams; - params.mMode = Utils.getKeyboardMode(editorInfo); + params.mMode = getKeyboardMode(editorInfo); params.mEditorInfo = (editorInfo != null) ? editorInfo : EMPTY_EDITOR_INFO; - params.mNoSettingsKey = Utils.inPrivateImeOptions( + params.mNoSettingsKey = StringUtils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, mEditorInfo); } @@ -230,7 +232,7 @@ public class KeyboardSet { // TODO: Use InputMethodSubtype object as argument. public Builder setSubtype(Locale inputLocale, boolean asciiCapable, boolean touchPositionCorrectionEnabled) { - final boolean deprecatedForceAscii = Utils.inPrivateImeOptions( + final boolean deprecatedForceAscii = StringUtils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii( mParams.mEditorInfo.imeOptions) @@ -243,9 +245,9 @@ public class KeyboardSet { public Builder setOptions(boolean voiceKeyEnabled, boolean voiceKeyOnMain, boolean languageSwitchKeyEnabled) { @SuppressWarnings("deprecation") - final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions( + final boolean deprecatedNoMicrophone = StringUtils.inPrivateImeOptions( null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); - final boolean noMicrophone = Utils.inPrivateImeOptions( + final boolean noMicrophone = StringUtils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; @@ -337,6 +339,44 @@ public class KeyboardSet { a.recycle(); } } + + private static int getKeyboardMode(EditorInfo editorInfo) { + if (editorInfo == null) + return KeyboardId.MODE_TEXT; + + final int inputType = editorInfo.inputType; + final int variation = inputType & InputType.TYPE_MASK_VARIATION; + + switch (inputType & InputType.TYPE_MASK_CLASS) { + case InputType.TYPE_CLASS_NUMBER: + return KeyboardId.MODE_NUMBER; + case InputType.TYPE_CLASS_DATETIME: + switch (variation) { + case InputType.TYPE_DATETIME_VARIATION_DATE: + return KeyboardId.MODE_DATE; + case InputType.TYPE_DATETIME_VARIATION_TIME: + return KeyboardId.MODE_TIME; + default: // InputType.TYPE_DATETIME_VARIATION_NORMAL + return KeyboardId.MODE_DATETIME; + } + case InputType.TYPE_CLASS_PHONE: + return KeyboardId.MODE_PHONE; + case InputType.TYPE_CLASS_TEXT: + if (InputTypeCompatUtils.isEmailVariation(variation)) { + return KeyboardId.MODE_EMAIL; + } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) { + return KeyboardId.MODE_URL; + } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { + return KeyboardId.MODE_IM; + } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { + return KeyboardId.MODE_TEXT; + } else { + return KeyboardId.MODE_TEXT; + } + default: + return KeyboardId.MODE_TEXT; + } + } } public static String parseKeyboardLocale(Resources res, int resId) diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 78e0ee230..decd73d45 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -41,7 +41,7 @@ import com.android.inputmethod.compat.FrameLayoutCompatUtils; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.StringUtils; import java.util.HashMap; @@ -853,7 +853,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (key.mLabel != null) { // TODO Should take care of temporaryShiftLabel here. previewText.setCompoundDrawables(null, null, null, null); - if (Utils.codePointCount(key.mLabel) > 1) { + if (StringUtils.codePointCount(key.mLabel) > 1) { previewText.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mKeyLetterSize); previewText.setTypeface(Typeface.DEFAULT_BOLD); } else { diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index afc4932e9..0a0307500 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -46,6 +46,8 @@ import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; +import com.android.inputmethod.latin.StringUtils; +import com.android.inputmethod.latin.SubtypeUtils; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; @@ -779,12 +781,13 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // Whether space key needs to show the "..." popup hint for special purposes if (mIsSpacebarTriggeringPopupByLongPress - && Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + && SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes( + true /* include aux subtypes */)) { drawKeyPopupHint(key, canvas, paint, params); } } else if (key.mCode == Keyboard.CODE_LANGUAGE_SWITCH) { super.onDrawKeyTopVisuals(key, canvas, paint, params); - if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { drawKeyPopupHint(key, canvas, paint, params); } } else { @@ -810,7 +813,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke paint.setTextAlign(Align.CENTER); paint.setTypeface(Typeface.DEFAULT); // Estimate appropriate language name text size to fit in maxTextWidth. - String language = Utils.getFullDisplayName(locale, true); + String language = StringUtils.getFullDisplayName(locale, true); int textWidth = getTextWidth(paint, language, origTextSize); // Assuming text width and text size are proportional to each other. float textSize = origTextSize * Math.min(width / textWidth, 1.0f); @@ -822,7 +825,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final boolean useShortName; if (useMiddleName) { - language = Utils.getMiddleDisplayLanguage(locale); + language = StringUtils.getMiddleDisplayLanguage(locale); textWidth = getTextWidth(paint, language, origTextSize); textSize = origTextSize * Math.min(width / textWidth, 1.0f); useShortName = (textSize / origTextSize < MINIMUM_SCALE_OF_LANGUAGE_NAME) @@ -832,7 +835,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } if (useShortName) { - language = Utils.getShortDisplayLanguage(locale); + language = StringUtils.getShortDisplayLanguage(locale); textWidth = getTextWidth(paint, language, origTextSize); textSize = origTextSize * Math.min(width / textWidth, 1.0f); } diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java index 9f735cff7..904a81de4 100644 --- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java +++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java @@ -22,7 +22,7 @@ import android.graphics.drawable.Drawable; import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.StringUtils; public class MoreKeysKeyboard extends Keyboard { private final int mDefaultKeyCoordX; @@ -301,7 +301,7 @@ public class MoreKeysKeyboard extends Keyboard { for (String moreKeySpec : parentKey.mMoreKeys) { final String label = KeySpecParser.getLabel(moreKeySpec); // If the label is single letter, minKeyWidth is enough to hold the label. - if (label != null && Utils.codePointCount(label) > 1) { + if (label != null && StringUtils.codePointCount(label) > 1) { if (paint == null) { paint = new Paint(); paint.setAntiAlias(true); diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java index f96f71e8a..582509324 100644 --- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java +++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java @@ -19,7 +19,7 @@ package com.android.inputmethod.keyboard; import android.graphics.Rect; import com.android.inputmethod.keyboard.Keyboard.Params.TouchPositionCorrection; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.JniUtils; import com.android.inputmethod.latin.spellcheck.SpellCheckerProximityInfo; import java.util.Arrays; @@ -81,7 +81,7 @@ public class ProximityInfo { private long mNativeProximityInfo; static { - Utils.loadNativeLibrary(); + JniUtils.loadNativeLibrary(); } private native long setProximityInfoNative(int maxProximityCharsSize, int displayWidth, diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java index e3fea3dce..0aba813b2 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java @@ -22,7 +22,7 @@ import android.text.TextUtils; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.Utils; +import com.android.inputmethod.latin.StringUtils; import java.util.ArrayList; import java.util.Arrays; @@ -150,7 +150,7 @@ public class KeySpecParser { } final String outputText = getOutputTextInternal(moreKeySpec); if (outputText != null) { - if (Utils.codePointCount(outputText) == 1) { + if (StringUtils.codePointCount(outputText) == 1) { // If output text is one code point, it should be treated as a code. // See {@link #getCode(Resources, String)}. return null; @@ -165,7 +165,7 @@ public class KeySpecParser { throw new KeySpecParserError("Empty label: " + moreKeySpec); } // Code is automatically generated for one letter label. See {@link getCode()}. - return (Utils.codePointCount(label) == 1) ? null : label; + return (StringUtils.codePointCount(label) == 1) ? null : label; } public static int getCode(Resources res, String moreKeySpec) { @@ -184,14 +184,14 @@ public class KeySpecParser { if (outputText != null) { // If output text is one code point, it should be treated as a code. // See {@link #getOutputText(String)}. - if (Utils.codePointCount(outputText) == 1) { + if (StringUtils.codePointCount(outputText) == 1) { return outputText.codePointAt(0); } return Keyboard.CODE_OUTPUT_TEXT; } final String label = getLabel(moreKeySpec); // Code is automatically generated for one letter label. - if (Utils.codePointCount(label) == 1) { + if (StringUtils.codePointCount(label) == 1) { return label.codePointAt(0); } return Keyboard.CODE_OUTPUT_TEXT; @@ -393,7 +393,7 @@ public class KeySpecParser { if (size == 0) { return null; } - if (Utils.codePointCount(text) == 1) { + if (StringUtils.codePointCount(text) == 1) { return text.codePointAt(0) == COMMA ? null : new String[] { text }; } diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 90ced6028..31ff4e7b4 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -104,7 +104,7 @@ public class BinaryDictionary extends Dictionary { } static { - Utils.loadNativeLibrary(); + JniUtils.loadNativeLibrary(); } private native long openNative(String sourceDir, long dictOffset, long dictSize, diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index 1607f86a8..7a81f7bd5 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -164,7 +164,7 @@ public class DictionaryFactory { final Resources res = context.getResources(); final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); - final int resourceId = Utils.getMainDictionaryResourceId(res); + final int resourceId = getMainDictionaryResourceId(res); final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); final boolean hasDictionary = isFullDictionary(afd); try { @@ -182,7 +182,7 @@ public class DictionaryFactory { final Resources res = context.getResources(); final Locale saveLocale = LocaleUtils.setSystemLocale(res, locale); - final int resourceId = Utils.getMainDictionaryResourceId(res); + final int resourceId = getMainDictionaryResourceId(res); final AssetFileDescriptor afd = res.openRawResourceFd(resourceId); final Long size = (afd != null && afd.getLength() > PLACEHOLDER_LENGTH) ? afd.getLength() @@ -209,4 +209,14 @@ public class DictionaryFactory { protected static boolean isFullDictionary(final AssetFileDescriptor afd) { return (afd != null && afd.getLength() > PLACEHOLDER_LENGTH); } + + /** + * Returns a main dictionary resource id + * @return main dictionary resource id + */ + public static int getMainDictionaryResourceId(Resources res) { + final String MAIN_DIC_NAME = "main"; + String packageName = LatinIME.class.getPackage().getName(); + return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName); + } } diff --git a/java/src/com/android/inputmethod/latin/JniUtils.java b/java/src/com/android/inputmethod/latin/JniUtils.java new file mode 100644 index 000000000..4808b867a --- /dev/null +++ b/java/src/com/android/inputmethod/latin/JniUtils.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 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.util.Log; + +import com.android.inputmethod.latin.define.JniLibName; + +public class JniUtils { + private static final String TAG = JniUtils.class.getSimpleName(); + + private JniUtils() { + // This utility class is not publicly instantiable. + } + + public static void loadNativeLibrary() { + try { + System.loadLibrary(JniLibName.JNI_LIB_NAME); + } catch (UnsatisfiedLinkError ule) { + Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME); + if (LatinImeLogger.sDBG) { + throw new RuntimeException( + "Could not load native library " + JniLibName.JNI_LIB_NAME); + } + } + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 1858db949..c16a34fac 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -44,8 +44,8 @@ import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; -import android.view.ViewParent; import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; import android.view.inputmethod.CompletionInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; @@ -576,7 +576,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar oldContactsDictionary = null; } - int mainDicResId = Utils.getMainDictionaryResourceId(res); + int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(res); mSuggest = new Suggest(this, mainDicResId, keyboardLocale); if (mSettingsValues.mAutoCorrectEnabled) { mSuggest.setAutoCorrectionThreshold(mSettingsValues.mAutoCorrectionThreshold); @@ -636,7 +636,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar /* package private */ void resetSuggestMainDict() { final String localeStr = mSubtypeSwitcher.getInputLocaleStr(); final Locale keyboardLocale = LocaleUtils.constructLocaleFromString(localeStr); - int mainDicResId = Utils.getMainDictionaryResourceId(mResources); + int mainDicResId = DictionaryFactory.getMainDictionaryResourceId(mResources); mSuggest.resetMainDict(this, mainDicResId, keyboardLocale); } @@ -745,12 +745,12 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar + String.format("inputType=0x%08x imeOptions=0x%08x", editorInfo.inputType, editorInfo.imeOptions)); } - if (Utils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { + if (StringUtils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); } - if (Utils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { + if (StringUtils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions); Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); @@ -1207,7 +1207,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic == null) return false; final CharSequence lastThree = ic.getTextBeforeCursor(3, 0); if (lastThree != null && lastThree.length() == 3 - && Utils.canBeFollowedByPeriod(lastThree.charAt(0)) + && StringUtils.canBeFollowedByPeriod(lastThree.charAt(0)) && lastThree.charAt(1) == Keyboard.CODE_SPACE && lastThree.charAt(2) == Keyboard.CODE_SPACE && mHandler.isAcceptingDoubleSpaces()) { @@ -1247,7 +1247,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isShowingOptionDialog()) return; if (InputMethodServiceCompatWrapper.CAN_HANDLE_ON_CURRENT_INPUT_METHOD_SUBTYPE_CHANGED) { showSubtypeSelectorAndSettings(); - } else if (Utils.hasMultipleEnabledIMEsOrSubtypes(false /* exclude aux subtypes */)) { + } else if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes( + false /* exclude aux subtypes */)) { showOptionsMenu(); } else { launchSettings(); @@ -1263,7 +1264,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (isShowingOptionDialog()) return false; switch (requestCode) { case CODE_SHOW_INPUT_METHOD_PICKER: - if (Utils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { + if (SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(true /* include aux subtypes */)) { mImm.showInputMethodPicker(); return true; } @@ -1295,7 +1296,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final IBinder token = getWindow().getWindow().getAttributes().token; if (mShouldSwitchToLastSubtype) { final InputMethodSubtypeCompatWrapper lastSubtype = mImm.getLastInputMethodSubtype(); - final boolean lastSubtypeBelongsToThisIme = Utils.checkIfSubtypeBelongsToThisIme( + final boolean lastSubtypeBelongsToThisIme = SubtypeUtils.checkIfSubtypeBelongsToThisIme( this, lastSubtype); if ((includesOtherImes || lastSubtypeBelongsToThisIme) && mImm.switchToLastInputMethod(token)) { @@ -1884,7 +1885,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar builder.addTypedWordAndPreviousSuggestions(typedWord, previousSuggestions); } } - if (Utils.shouldBlockAutoCorrectionBySafetyNet(builder, mSuggest)) { + if (Suggest.shouldBlockAutoCorrectionBySafetyNet(builder, mSuggest)) { builder.setShouldBlockAutoCorrectionBySafetyNet(); } showSuggestions(builder.build(), typedWord); @@ -2486,7 +2487,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar switch (position) { case 0: Intent intent = CompatUtils.getInputLanguageSelectionIntent( - Utils.getInputMethodId(getPackageName()), + SubtypeUtils.getInputMethodId(getPackageName()), Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED | Intent.FLAG_ACTIVITY_CLEAR_TOP); diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 305cef22d..72391f31e 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -343,7 +343,7 @@ public class Settings extends InputMethodSettingsActivity @Override public boolean onPreferenceClick(Preference pref) { if (pref == mInputLanguageSelection) { - final String imeId = Utils.getInputMethodId( + final String imeId = SubtypeUtils.getInputMethodId( getActivityInternal().getApplicationInfo().packageName); startActivity(CompatUtils.getInputLanguageSelectionIntent(imeId, 0)); return true; diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 69e45f619..abd1dc692 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -326,9 +326,9 @@ public class SettingsValues { return false; } if (mIncludesOtherImesInLanguageSwitchList) { - return Utils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false); + return SubtypeUtils.hasMultipleEnabledIMEsOrSubtypes(/* include aux subtypes */false); } else { - return Utils.hasMultipleEnabledSubtypesInThisIme( + return SubtypeUtils.hasMultipleEnabledSubtypesInThisIme( context, /* include aux subtypes */false); } } diff --git a/java/src/com/android/inputmethod/latin/StringUtils.java b/java/src/com/android/inputmethod/latin/StringUtils.java new file mode 100644 index 000000000..81c3b4edf --- /dev/null +++ b/java/src/com/android/inputmethod/latin/StringUtils.java @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2012 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.text.TextUtils; +import android.view.inputmethod.EditorInfo; + +import com.android.inputmethod.keyboard.Keyboard; + +import java.util.ArrayList; +import java.util.Locale; + +public class StringUtils { + private StringUtils() { + // This utility class is not publicly instantiable. + } + + public static boolean canBeFollowedByPeriod(final int codePoint) { + // TODO: Check again whether there really ain't a better way to check this. + // TODO: This should probably be language-dependant... + return Character.isLetterOrDigit(codePoint) + || codePoint == Keyboard.CODE_SINGLE_QUOTE + || codePoint == Keyboard.CODE_DOUBLE_QUOTE + || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS + || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET + || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET + || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; + } + + public static int codePointCount(String text) { + if (TextUtils.isEmpty(text)) return 0; + return text.codePointCount(0, text.length()); + } + + public static boolean containsInCsv(String key, String csv) { + if (csv == null) + return false; + for (String option : csv.split(",")) { + if (option.equals(key)) + return true; + } + return false; + } + + public static boolean inPrivateImeOptions(String packageName, String key, + EditorInfo editorInfo) { + if (editorInfo == null) + return false; + return containsInCsv(packageName != null ? packageName + "." + key : key, + editorInfo.privateImeOptions); + } + + /** + * Returns true if a and b are equal ignoring the case of the character. + * @param a first character to check + * @param b second character to check + * @return {@code true} if a and b are equal, {@code false} otherwise. + */ + public static boolean equalsIgnoreCase(char a, char b) { + // Some language, such as Turkish, need testing both cases. + return a == b + || Character.toLowerCase(a) == Character.toLowerCase(b) + || Character.toUpperCase(a) == Character.toUpperCase(b); + } + + /** + * Returns true if a and b are equal ignoring the case of the characters, including if they are + * both null. + * @param a first CharSequence to check + * @param b second CharSequence to check + * @return {@code true} if a and b are equal, {@code false} otherwise. + */ + public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) { + if (a == b) + return true; // including both a and b are null. + if (a == null || b == null) + return false; + final int length = a.length(); + if (length != b.length()) + return false; + for (int i = 0; i < length; i++) { + if (!equalsIgnoreCase(a.charAt(i), b.charAt(i))) + return false; + } + return true; + } + + /** + * Returns true if a and b are equal ignoring the case of the characters, including if a is null + * and b is zero length. + * @param a CharSequence to check + * @param b character array to check + * @param offset start offset of array b + * @param length length of characters in array b + * @return {@code true} if a and b are equal, {@code false} otherwise. + * @throws IndexOutOfBoundsException + * if {@code offset < 0 || length < 0 || offset + length > data.length}. + * @throws NullPointerException if {@code b == null}. + */ + public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) { + if (offset < 0 || length < 0 || length > b.length - offset) + throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset + + " length=" + length); + if (a == null) + return length == 0; // including a is null and b is zero length. + if (a.length() != length) + return false; + for (int i = 0; i < length; i++) { + if (!equalsIgnoreCase(a.charAt(i), b[offset + i])) + return false; + } + return true; + } + + /** + * Remove duplicates from an array of strings. + * + * This method will always keep the first occurence of all strings at their position + * in the array, removing the subsequent ones. + */ + public static void removeDupes(final ArrayList suggestions) { + if (suggestions.size() < 2) return; + int i = 1; + // Don't cache suggestions.size(), since we may be removing items + while (i < suggestions.size()) { + final CharSequence cur = suggestions.get(i); + // Compare each suggestion with each previous suggestion + for (int j = 0; j < i; j++) { + CharSequence previous = suggestions.get(j); + if (TextUtils.equals(cur, previous)) { + removeFromSuggestions(suggestions, i); + i--; + break; + } + } + i++; + } + } + + private static void removeFromSuggestions(final ArrayList suggestions, + final int index) { + final CharSequence garbage = suggestions.remove(index); + if (garbage instanceof StringBuilder) { + StringBuilderPool.recycle((StringBuilder)garbage); + } + } + + public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { + if (returnsNameInThisLocale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } else { + return toTitleCase(locale.getDisplayName(), locale); + } + } + + public static String getDisplayLanguage(Locale locale) { + return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); + } + + public static String getMiddleDisplayLanguage(Locale locale) { + return toTitleCase((LocaleUtils.constructLocaleFromString( + locale.getLanguage()).getDisplayLanguage(locale)), locale); + } + + public static String getShortDisplayLanguage(Locale locale) { + return toTitleCase(locale.getLanguage(), locale); + } + + public static String toTitleCase(String s, Locale locale) { + if (s.length() <= 1) { + // TODO: is this really correct? Shouldn't this be s.toUpperCase()? + return s; + } + // TODO: fix the bugs below + // - This does not work for Greek, because it returns upper case instead of title case. + // - It does not work for Serbian, because it fails to account for the "lj" character, + // which should be "Lj" in title case and "LJ" in upper case. + // - It does not work for Dutch, because it fails to account for the "ij" digraph, which + // are two different characters but both should be capitalized as "IJ" as if they were + // a single letter. + // - It also does not work with unicode surrogate code points. + return s.toUpperCase(locale).charAt(0) + s.substring(1); + } +} diff --git a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java index f5778167a..ffbbf9bb8 100644 --- a/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java +++ b/java/src/com/android/inputmethod/latin/SubtypeSwitcher.java @@ -512,7 +512,7 @@ public class SubtypeSwitcher { } public String getInputLanguageName() { - return Utils.getDisplayLanguage(getInputLocale()); + return StringUtils.getDisplayLanguage(getInputLocale()); } ///////////////////////////// diff --git a/java/src/com/android/inputmethod/latin/SubtypeUtils.java b/java/src/com/android/inputmethod/latin/SubtypeUtils.java new file mode 100644 index 000000000..cb2bcf43f --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SubtypeUtils.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2012 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 com.android.inputmethod.compat.InputMethodInfoCompatWrapper; +import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; + +import java.util.Collections; +import java.util.List; + +public class SubtypeUtils { + private SubtypeUtils() { + // This utility class is not publicly instantiable. + } + + // TODO: Cache my InputMethodInfo and/or InputMethodSubtype list. + public static boolean checkIfSubtypeBelongsToThisIme(Context context, + InputMethodSubtypeCompatWrapper ims) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; + + final InputMethodInfoCompatWrapper myImi = getInputMethodInfo(context.getPackageName()); + final List subtypes = + imm.getEnabledInputMethodSubtypeList(myImi, true); + for (final InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (subtype.equals(ims)) { + return true; + } + } + return false; + } + + public static boolean hasMultipleEnabledIMEsOrSubtypes( + final boolean shouldIncludeAuxiliarySubtypes) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; + + final List enabledImis = imm.getEnabledInputMethodList(); + return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); + } + + public static boolean hasMultipleEnabledSubtypesInThisIme(Context context, + final boolean shouldIncludeAuxiliarySubtypes) { + final InputMethodInfoCompatWrapper myImi = getInputMethodInfo(context.getPackageName()); + final List imiList = Collections.singletonList(myImi); + return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); + } + + private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, + List imiList) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) return false; + + // Number of the filtered IMEs + int filteredImisCount = 0; + + for (InputMethodInfoCompatWrapper imi : imiList) { + // We can return true immediately after we find two or more filtered IMEs. + if (filteredImisCount > 1) return true; + final List subtypes = + imm.getEnabledInputMethodSubtypeList(imi, true); + // IMEs that have no subtypes should be counted. + if (subtypes.isEmpty()) { + ++filteredImisCount; + continue; + } + + int auxCount = 0; + for (InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (subtype.isAuxiliary()) { + ++auxCount; + } + } + final int nonAuxCount = subtypes.size() - auxCount; + + // IMEs that have one or more non-auxiliary subtypes should be counted. + // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary + // subtypes should be counted as well. + if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { + ++filteredImisCount; + continue; + } + } + + if (filteredImisCount > 1) { + return true; + } + final List subtypes = + imm.getEnabledInputMethodSubtypeList(null, true); + int keyboardCount = 0; + // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's + // both explicitly and implicitly enabled input method subtype. + // (The current IME should be LatinIME.) + for (InputMethodSubtypeCompatWrapper subtype : subtypes) { + if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) { + ++keyboardCount; + } + } + return keyboardCount > 1; + } + + public static String getInputMethodId(String packageName) { + return getInputMethodInfo(packageName).getId(); + } + + public static InputMethodInfoCompatWrapper getInputMethodInfo(String packageName) { + final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); + if (imm == null) { + throw new RuntimeException("Input method manager not found"); + } + + for (final InputMethodInfoCompatWrapper imi : imm.getEnabledInputMethodList()) { + if (imi.getPackageName().equals(packageName)) + return imi; + } + throw new RuntimeException("Can not find input method id for " + packageName); + } +} diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 298ead665..671fb905d 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -108,6 +108,8 @@ public class Suggest implements Dictionary.WordCallback { private boolean mIsAllUpperCase; private int mTrailingSingleQuotesCount; + private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; + public Suggest(final Context context, final int dictionaryResId, final Locale locale) { initAsynchronously(context, dictionaryResId, locale); } @@ -383,7 +385,7 @@ public class Suggest implements Dictionary.WordCallback { if (typedWord != null) { mSuggestions.add(0, typedWord.toString()); } - Utils.removeDupes(mSuggestions); + StringUtils.removeDupes(mSuggestions); if (DBG) { double normalizedScore = mAutoCorrection.getNormalizedScore(); @@ -434,7 +436,7 @@ public class Suggest implements Dictionary.WordCallback { int pos = 0; // Check if it's the same word, only caps are different - if (Utils.equalsIgnoreCase(mConsideredWord, word, offset, length)) { + if (StringUtils.equalsIgnoreCase(mConsideredWord, word, offset, length)) { // TODO: remove this surrounding if clause and move this logic to // getSuggestedWordBuilder. if (suggestions.size() > 0) { @@ -443,7 +445,7 @@ public class Suggest implements Dictionary.WordCallback { // frequency to determine the insertion position. This does not ensure strictly // correct ordering, but ensures the top score is on top which is enough for // removing duplicates correctly. - if (Utils.equalsIgnoreCase(currentHighestWord, word, offset, length) + if (StringUtils.equalsIgnoreCase(currentHighestWord, word, offset, length) && score <= sortedScores[0]) { pos = 1; } @@ -558,4 +560,46 @@ public class Suggest implements Dictionary.WordCallback { } mMainDict = null; } + + // TODO: Resolve the inconsistencies between the native auto correction algorithms and + // this safety net + public static boolean shouldBlockAutoCorrectionBySafetyNet( + SuggestedWords.Builder suggestedWordsBuilder, Suggest suggest) { + // Safety net for auto correction. + // Actually if we hit this safety net, it's actually a bug. + if (suggestedWordsBuilder.size() <= 1 || suggestedWordsBuilder.isTypedWordValid()) { + return false; + } + // If user selected aggressive auto correction mode, there is no need to use the safety + // net. + if (suggest.isAggressiveAutoCorrectionMode()) { + return false; + } + final CharSequence typedWord = suggestedWordsBuilder.getWord(0); + // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, + // we should not use net because relatively edit distance can be big. + if (typedWord.length() < Suggest.MINIMUM_SAFETY_NET_CHAR_LENGTH) { + return false; + } + final CharSequence suggestionWord = suggestedWordsBuilder.getWord(1); + final int typedWordLength = typedWord.length(); + final int maxEditDistanceOfNativeDictionary = + (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; + final int distance = BinaryDictionary.editDistance( + typedWord.toString(), suggestionWord.toString()); + if (DBG) { + Log.d(TAG, "Autocorrected edit distance = " + distance + + ", " + maxEditDistanceOfNativeDictionary); + } + if (distance > maxEditDistanceOfNativeDictionary) { + if (DBG) { + Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord); + Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. " + + "Turning off auto-correction."); + } + return true; + } else { + return false; + } + } } diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a8679e07a..f8dd5ae42 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -19,7 +19,6 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.AsyncTask; @@ -27,19 +26,9 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; -import android.text.InputType; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; -import android.view.inputmethod.EditorInfo; - -import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; -import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; -import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; -import com.android.inputmethod.compat.InputTypeCompatUtils; -import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.keyboard.KeyboardId; -import com.android.inputmethod.latin.define.JniLibName; import java.io.BufferedReader; import java.io.File; @@ -51,20 +40,11 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; import java.util.Date; -import java.util.List; -import java.util.Locale; public class Utils { - private static final String TAG = Utils.class.getSimpleName(); - private static final int MINIMUM_SAFETY_NET_CHAR_LENGTH = 4; - private static boolean DBG = LatinImeLogger.sDBG; - private static boolean DBG_EDIT_DISTANCE = false; - private Utils() { - // Intentional empty constructor for utility class. + // This utility class is not publicly instantiable. } /** @@ -118,166 +98,6 @@ public class Utils { } } - // TODO: Move InputMethodSubtype related utility methods to its own utility class. - // TODO: Cache my InputMethodInfo and/or InputMethodSubtype list. - public static boolean checkIfSubtypeBelongsToThisIme(Context context, - InputMethodSubtypeCompatWrapper ims) { - final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); - if (imm == null) return false; - - final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( - context.getPackageName()); - final List subtypes = - imm.getEnabledInputMethodSubtypeList(myImi, true); - for (final InputMethodSubtypeCompatWrapper subtype : subtypes) { - if (subtype.equals(ims)) { - return true; - } - } - return false; - } - - public static boolean hasMultipleEnabledIMEsOrSubtypes( - final boolean shouldIncludeAuxiliarySubtypes) { - final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); - if (imm == null) return false; - - final List enabledImis = imm.getEnabledInputMethodList(); - return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); - } - - public static boolean hasMultipleEnabledSubtypesInThisIme(Context context, - final boolean shouldIncludeAuxiliarySubtypes) { - final InputMethodInfoCompatWrapper myImi = Utils.getInputMethodInfo( - context.getPackageName()); - final List imiList = Collections.singletonList(myImi); - return Utils.hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); - } - - private static boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, - List imiList) { - final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); - if (imm == null) return false; - - // Number of the filtered IMEs - int filteredImisCount = 0; - - for (InputMethodInfoCompatWrapper imi : imiList) { - // We can return true immediately after we find two or more filtered IMEs. - if (filteredImisCount > 1) return true; - final List subtypes = - imm.getEnabledInputMethodSubtypeList(imi, true); - // IMEs that have no subtypes should be counted. - if (subtypes.isEmpty()) { - ++filteredImisCount; - continue; - } - - int auxCount = 0; - for (InputMethodSubtypeCompatWrapper subtype : subtypes) { - if (subtype.isAuxiliary()) { - ++auxCount; - } - } - final int nonAuxCount = subtypes.size() - auxCount; - - // IMEs that have one or more non-auxiliary subtypes should be counted. - // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary - // subtypes should be counted as well. - if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { - ++filteredImisCount; - continue; - } - } - - if (filteredImisCount > 1) { - return true; - } - final List subtypes = - imm.getEnabledInputMethodSubtypeList(null, true); - int keyboardCount = 0; - // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's - // both explicitly and implicitly enabled input method subtype. - // (The current IME should be LatinIME.) - for (InputMethodSubtypeCompatWrapper subtype : subtypes) { - if (SubtypeSwitcher.KEYBOARD_MODE.equals(subtype.getMode())) { - ++keyboardCount; - } - } - return keyboardCount > 1; - } - - public static String getInputMethodId(String packageName) { - return getInputMethodInfo(packageName).getId(); - } - - public static InputMethodInfoCompatWrapper getInputMethodInfo(String packageName) { - final InputMethodManagerCompatWrapper imm = InputMethodManagerCompatWrapper.getInstance(); - if (imm == null) { - throw new RuntimeException("Input method manager not found"); - } - - for (final InputMethodInfoCompatWrapper imi : imm.getEnabledInputMethodList()) { - if (imi.getPackageName().equals(packageName)) - return imi; - } - throw new RuntimeException("Can not find input method id for " + packageName); - } - - // TODO: Resolve the inconsistencies between the native auto correction algorithms and - // this safety net - public static boolean shouldBlockAutoCorrectionBySafetyNet( - SuggestedWords.Builder suggestedWordsBuilder, Suggest suggest) { - // Safety net for auto correction. - // Actually if we hit this safety net, it's actually a bug. - if (suggestedWordsBuilder.size() <= 1 || suggestedWordsBuilder.isTypedWordValid()) { - return false; - } - // If user selected aggressive auto correction mode, there is no need to use the safety - // net. - if (suggest.isAggressiveAutoCorrectionMode()) { - return false; - } - final CharSequence typedWord = suggestedWordsBuilder.getWord(0); - // If the length of typed word is less than MINIMUM_SAFETY_NET_CHAR_LENGTH, - // we should not use net because relatively edit distance can be big. - if (typedWord.length() < MINIMUM_SAFETY_NET_CHAR_LENGTH) { - return false; - } - final CharSequence suggestionWord = suggestedWordsBuilder.getWord(1); - final int typedWordLength = typedWord.length(); - final int maxEditDistanceOfNativeDictionary = - (typedWordLength < 5 ? 2 : typedWordLength / 2) + 1; - final int distance = BinaryDictionary.editDistance( - typedWord.toString(), suggestionWord.toString()); - if (DBG) { - Log.d(TAG, "Autocorrected edit distance = " + distance - + ", " + maxEditDistanceOfNativeDictionary); - } - if (distance > maxEditDistanceOfNativeDictionary) { - if (DBG) { - Log.e(TAG, "Safety net: before = " + typedWord + ", after = " + suggestionWord); - Log.e(TAG, "(Error) The edit distance of this correction exceeds limit. " - + "Turning off auto-correction."); - } - return true; - } else { - return false; - } - } - - public static boolean canBeFollowedByPeriod(final int codePoint) { - // TODO: Check again whether there really ain't a better way to check this. - // TODO: This should probably be language-dependant... - return Character.isLetterOrDigit(codePoint) - || codePoint == Keyboard.CODE_SINGLE_QUOTE - || codePoint == Keyboard.CODE_DOUBLE_QUOTE - || codePoint == Keyboard.CODE_CLOSING_PARENTHESIS - || codePoint == Keyboard.CODE_CLOSING_SQUARE_BRACKET - || codePoint == Keyboard.CODE_CLOSING_CURLY_BRACKET - || codePoint == Keyboard.CODE_CLOSING_ANGLE_BRACKET; - } - /* package */ static class RingCharBuffer { private static RingCharBuffer sRingCharBuffer = new RingCharBuffer(); private static final char PLACEHOLDER_DELIMITER_CHAR = '\uFFFC'; @@ -600,147 +420,6 @@ public class Utils { } } - // TODO: Move this method to KeyboardSet class. - public static int getKeyboardMode(EditorInfo editorInfo) { - if (editorInfo == null) - return KeyboardId.MODE_TEXT; - - final int inputType = editorInfo.inputType; - final int variation = inputType & InputType.TYPE_MASK_VARIATION; - - switch (inputType & InputType.TYPE_MASK_CLASS) { - case InputType.TYPE_CLASS_NUMBER: - return KeyboardId.MODE_NUMBER; - case InputType.TYPE_CLASS_DATETIME: - switch (variation) { - case InputType.TYPE_DATETIME_VARIATION_DATE: - return KeyboardId.MODE_DATE; - case InputType.TYPE_DATETIME_VARIATION_TIME: - return KeyboardId.MODE_TIME; - default: // InputType.TYPE_DATETIME_VARIATION_NORMAL - return KeyboardId.MODE_DATETIME; - } - case InputType.TYPE_CLASS_PHONE: - return KeyboardId.MODE_PHONE; - case InputType.TYPE_CLASS_TEXT: - if (InputTypeCompatUtils.isEmailVariation(variation)) { - return KeyboardId.MODE_EMAIL; - } else if (variation == InputType.TYPE_TEXT_VARIATION_URI) { - return KeyboardId.MODE_URL; - } else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) { - return KeyboardId.MODE_IM; - } else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) { - return KeyboardId.MODE_TEXT; - } else { - return KeyboardId.MODE_TEXT; - } - default: - return KeyboardId.MODE_TEXT; - } - } - - public static boolean containsInCsv(String key, String csv) { - if (csv == null) - return false; - for (String option : csv.split(",")) { - if (option.equals(key)) - return true; - } - return false; - } - - public static boolean inPrivateImeOptions(String packageName, String key, - EditorInfo editorInfo) { - if (editorInfo == null) - return false; - return containsInCsv(packageName != null ? packageName + "." + key : key, - editorInfo.privateImeOptions); - } - - /** - * Returns a main dictionary resource id - * @return main dictionary resource id - */ - public static int getMainDictionaryResourceId(Resources res) { - final String MAIN_DIC_NAME = "main"; - String packageName = LatinIME.class.getPackage().getName(); - return res.getIdentifier(MAIN_DIC_NAME, "raw", packageName); - } - - public static void loadNativeLibrary() { - try { - System.loadLibrary(JniLibName.JNI_LIB_NAME); - } catch (UnsatisfiedLinkError ule) { - Log.e(TAG, "Could not load native library " + JniLibName.JNI_LIB_NAME); - if (LatinImeLogger.sDBG) { - throw new RuntimeException( - "Could not load native library " + JniLibName.JNI_LIB_NAME); - } - } - } - - /** - * Returns true if a and b are equal ignoring the case of the character. - * @param a first character to check - * @param b second character to check - * @return {@code true} if a and b are equal, {@code false} otherwise. - */ - public static boolean equalsIgnoreCase(char a, char b) { - // Some language, such as Turkish, need testing both cases. - return a == b - || Character.toLowerCase(a) == Character.toLowerCase(b) - || Character.toUpperCase(a) == Character.toUpperCase(b); - } - - /** - * Returns true if a and b are equal ignoring the case of the characters, including if they are - * both null. - * @param a first CharSequence to check - * @param b second CharSequence to check - * @return {@code true} if a and b are equal, {@code false} otherwise. - */ - public static boolean equalsIgnoreCase(CharSequence a, CharSequence b) { - if (a == b) - return true; // including both a and b are null. - if (a == null || b == null) - return false; - final int length = a.length(); - if (length != b.length()) - return false; - for (int i = 0; i < length; i++) { - if (!equalsIgnoreCase(a.charAt(i), b.charAt(i))) - return false; - } - return true; - } - - /** - * Returns true if a and b are equal ignoring the case of the characters, including if a is null - * and b is zero length. - * @param a CharSequence to check - * @param b character array to check - * @param offset start offset of array b - * @param length length of characters in array b - * @return {@code true} if a and b are equal, {@code false} otherwise. - * @throws IndexOutOfBoundsException - * if {@code offset < 0 || length < 0 || offset + length > data.length}. - * @throws NullPointerException if {@code b == null}. - */ - public static boolean equalsIgnoreCase(CharSequence a, char[] b, int offset, int length) { - if (offset < 0 || length < 0 || length > b.length - offset) - throw new IndexOutOfBoundsException("array.length=" + b.length + " offset=" + offset - + " length=" + length); - if (a == null) - return length == 0; // including a is null and b is zero length. - if (a.length() != length) - return false; - for (int i = 0; i < length; i++) { - if (!equalsIgnoreCase(a.charAt(i), b[offset + i])) - return false; - } - return true; - } - public static float getDipScale(Context context) { final float scale = context.getResources().getDisplayMetrics().density; return scale; @@ -751,76 +430,6 @@ public class Utils { return (int) (dip * scale + 0.5); } - /** - * Remove duplicates from an array of strings. - * - * This method will always keep the first occurence of all strings at their position - * in the array, removing the subsequent ones. - */ - public static void removeDupes(final ArrayList suggestions) { - if (suggestions.size() < 2) return; - int i = 1; - // Don't cache suggestions.size(), since we may be removing items - while (i < suggestions.size()) { - final CharSequence cur = suggestions.get(i); - // Compare each suggestion with each previous suggestion - for (int j = 0; j < i; j++) { - CharSequence previous = suggestions.get(j); - if (TextUtils.equals(cur, previous)) { - removeFromSuggestions(suggestions, i); - i--; - break; - } - } - i++; - } - } - - private static void removeFromSuggestions(final ArrayList suggestions, - final int index) { - final CharSequence garbage = suggestions.remove(index); - if (garbage instanceof StringBuilder) { - StringBuilderPool.recycle((StringBuilder)garbage); - } - } - - public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { - if (returnsNameInThisLocale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } else { - return toTitleCase(locale.getDisplayName(), locale); - } - } - - public static String getDisplayLanguage(Locale locale) { - return toTitleCase(SubtypeLocale.getFullDisplayName(locale), locale); - } - - public static String getMiddleDisplayLanguage(Locale locale) { - return toTitleCase((LocaleUtils.constructLocaleFromString( - locale.getLanguage()).getDisplayLanguage(locale)), locale); - } - - public static String getShortDisplayLanguage(Locale locale) { - return toTitleCase(locale.getLanguage(), locale); - } - - public static String toTitleCase(String s, Locale locale) { - if (s.length() <= 1) { - // TODO: is this really correct? Shouldn't this be s.toUpperCase()? - return s; - } - // TODO: fix the bugs below - // - This does not work for Greek, because it returns upper case instead of title case. - // - It does not work for Serbian, because it fails to account for the "lj" character, - // which should be "Lj" in title case and "LJ" in upper case. - // - It does not work for Dutch, because it fails to account for the "ij" digraph, which - // are two different characters but both should be capitalized as "IJ" as if they were - // a single letter. - // - It also does not work with unicode surrogate code points. - return s.toUpperCase(locale).charAt(0) + s.substring(1); - } - public static class Stats { public static void onNonSeparator(final char code, final int x, final int y) { @@ -845,9 +454,4 @@ public class Utils { LatinImeLogger.logOnAutoCorrectionCancelled(); } } - - public static int codePointCount(String text) { - if (TextUtils.isEmpty(text)) return 0; - return text.codePointCount(0, text.length()); - } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 755c75b2e..35a5c0f52 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -37,9 +37,9 @@ import com.android.inputmethod.latin.DictionaryFactory; import com.android.inputmethod.latin.Flag; import com.android.inputmethod.latin.LocaleUtils; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SynchronouslyLoadedContactsDictionary; import com.android.inputmethod.latin.SynchronouslyLoadedUserDictionary; -import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.WhitelistDictionary; import com.android.inputmethod.latin.WordComposer; @@ -47,11 +47,11 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.TreeMap; -import java.util.HashSet; /** * Service for spell checking, using LatinIME's dictionaries and mechanisms. @@ -316,7 +316,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService } } Collections.reverse(mSuggestions); - Utils.removeDupes(mSuggestions); + StringUtils.removeDupes(mSuggestions); if (CAPITALIZE_ALL == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // get(i) returns a CharSequence which is actually a String so .toString() @@ -326,7 +326,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService } else if (CAPITALIZE_FIRST == capitalizeType) { for (int i = 0; i < mSuggestions.size(); ++i) { // Likewise - mSuggestions.set(i, Utils.toTitleCase(mSuggestions.get(i).toString(), + mSuggestions.set(i, StringUtils.toTitleCase(mSuggestions.get(i).toString(), locale)); } } @@ -396,7 +396,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService final ProximityInfo proximityInfo = ProximityInfo.createSpellCheckerProximityInfo( SpellCheckerProximityInfo.getProximityForScript(script)); final Resources resources = getResources(); - final int fallbackResourceId = Utils.getMainDictionaryResourceId(resources); + final int fallbackResourceId = DictionaryFactory.getMainDictionaryResourceId(resources); final DictionaryCollection dictionaryCollection = DictionaryFactory.createDictionaryFromManager(this, locale, fallbackResourceId, USE_FULL_EDIT_DISTANCE_FLAG_ARRAY); -- cgit v1.2.3-83-g751a From 042557b45bf2554608cd22874633011157cd1752 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 15 Mar 2012 14:56:09 +0900 Subject: De-duplicate a method Change-Id: Ia1c80eeff00a55573bb311f07e1275da23bdcf98 --- java/src/com/android/inputmethod/latin/Utils.java | 11 +++++++++++ .../inputmethod/latin/suggestions/MoreSuggestions.java | 14 ++------------ .../inputmethod/latin/suggestions/SuggestionsView.java | 18 +++--------------- 3 files changed, 16 insertions(+), 27 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index f8dd5ae42..a7de47c58 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -30,6 +30,8 @@ import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -454,4 +456,13 @@ public class Utils { LatinImeLogger.logOnAutoCorrectionCancelled(); } } + + public static String getDebugInfo(final SuggestedWords suggestions, final int pos) { + if (!LatinImeLogger.sDBG) return null; + final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); + if (wordInfo == null) return null; + final String info = wordInfo.getDebugString(); + if (TextUtils.isEmpty(info)) return null; + return info; + } } diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java index cb1b49c67..c9c88fd23 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java +++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java @@ -19,7 +19,6 @@ package com.android.inputmethod.latin.suggestions; import android.content.res.Resources; import android.graphics.Paint; import android.graphics.drawable.Drawable; -import android.text.TextUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; @@ -29,7 +28,7 @@ import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; -import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.Utils; public class MoreSuggestions extends Keyboard { public static final int SUGGESTION_CODE_BASE = 1024; @@ -191,15 +190,6 @@ public class MoreSuggestions extends Keyboard { return this; } - private static String getDebugInfo(SuggestedWords suggestions, int pos) { - if (!DBG) return null; - final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); - if (wordInfo == null) return null; - final String info = wordInfo.getDebugString(); - if (TextUtils.isEmpty(info)) return null; - return info; - } - private static class Divider extends Key.Spacer { private final Drawable mIcon; @@ -223,7 +213,7 @@ public class MoreSuggestions extends Keyboard { final int y = params.getY(pos); final int width = params.getWidth(pos); final String word = mSuggestions.getWord(pos).toString(); - final String info = getDebugInfo(mSuggestions, pos); + final String info = Utils.getDebugInfo(mSuggestions, pos); final int index = pos + SUGGESTION_CODE_BASE; final Key key = new Key( params, word, info, KeyboardIconsSet.ICON_UNDEFINED, index, null, x, y, diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java index b632f093f..d3c3afb73 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionsView.java @@ -63,6 +63,7 @@ import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.Suggest; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import com.android.inputmethod.latin.Utils; import java.util.ArrayList; import java.util.List; @@ -404,8 +405,8 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, word, getSuggestionWeight(index), ViewGroup.LayoutParams.MATCH_PARENT); x += word.getMeasuredWidth(); - if (DBG) { - final CharSequence debugInfo = getDebugInfo(suggestedWords, pos); + if (DBG && pos < suggestedWords.size()) { + final CharSequence debugInfo = Utils.getDebugInfo(suggestedWords, pos); if (debugInfo != null) { final TextView info = mInfos.get(pos); info.setText(debugInfo); @@ -500,19 +501,6 @@ public class SuggestionsView extends RelativeLayout implements OnClickListener, hintView, 1.0f - mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); } - private static String getDebugInfo(SuggestedWords suggestions, int pos) { - if (DBG && pos < suggestions.size()) { - final SuggestedWordInfo wordInfo = suggestions.getInfo(pos); - if (wordInfo != null) { - final String debugInfo = wordInfo.getDebugString(); - if (!TextUtils.isEmpty(debugInfo)) { - return debugInfo; - } - } - } - return null; - } - private static void setLayoutWeight(View v, float weight, int height) { final ViewGroup.LayoutParams lp = v.getLayoutParams(); if (lp instanceof LinearLayout.LayoutParams) { -- cgit v1.2.3-83-g751a From 140467b8b65eb9087a9b7f744dbb8a30481effe7 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Tue, 20 Mar 2012 23:29:34 +0900 Subject: Updated logger to record touch position within backspace key events. Bug: 6188932 Change-Id: Ida2aff618153792f9803f30f1251d67c89af1fe0 --- java/src/com/android/inputmethod/latin/LatinIME.java | 2 +- java/src/com/android/inputmethod/latin/LatinImeLogger.java | 2 +- java/src/com/android/inputmethod/latin/Utils.java | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 99a4d54d8..e67f0ea05 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1288,7 +1288,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mDeleteCount++; mExpectingUpdateSelection = true; mShouldSwitchToLastSubtype = true; - LatinImeLogger.logOnDelete(); + LatinImeLogger.logOnDelete(x, y); break; case Keyboard.CODE_SHIFT: case Keyboard.CODE_SWITCH_ALPHA_SYMBOL: diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 683dafa86..079f3b5dd 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -51,7 +51,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void logOnAutoCorrectionCancelled() { } - public static void logOnDelete() { + public static void logOnDelete(int x, int y) { } public static void logOnInputChar() { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a7de47c58..509bd368d 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -260,8 +260,8 @@ public class Utils { } } - public static void writeBackSpace() { - UsabilityStudyLogUtils.getInstance().write("\t0\t0"); + public static void writeBackSpace(int x, int y) { + UsabilityStudyLogUtils.getInstance().write("\t" + x + "\t" + y); } public void writeChar(char c, int x, int y) { -- cgit v1.2.3-83-g751a From 624f1bab39357eb716dfc7ec6b723da3f926f5a2 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 21 Mar 2012 15:33:55 +0900 Subject: Refactor to memorize device dependent override parameters Change-Id: I79482a8ef3846525669979a30dec183ea18138b5 --- .../sudden-jumping-touch-event-device-list.xml | 8 ++++---- .../keyboard/SuddenJumpingTouchEventHandler.java | 16 +++------------ .../android/inputmethod/latin/SettingsValues.java | 23 +++++----------------- java/src/com/android/inputmethod/latin/Utils.java | 22 +++++++++++++++++++++ 4 files changed, 34 insertions(+), 35 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/res/values/sudden-jumping-touch-event-device-list.xml b/java/res/values/sudden-jumping-touch-event-device-list.xml index ba828a758..543992a81 100644 --- a/java/res/values/sudden-jumping-touch-event-device-list.xml +++ b/java/res/values/sudden-jumping-touch-event-device-list.xml @@ -19,9 +19,9 @@ --> - - mahimahi - - sholes + + mahimahi,true + sholes,true diff --git a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java index 62a9259f9..347383f95 100644 --- a/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java +++ b/java/src/com/android/inputmethod/keyboard/SuddenJumpingTouchEventHandler.java @@ -17,12 +17,12 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.os.Build; import android.util.Log; import android.view.MotionEvent; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.Utils; public class SuddenJumpingTouchEventHandler { private static final String TAG = SuddenJumpingTouchEventHandler.class.getSimpleName(); @@ -49,18 +49,8 @@ public class SuddenJumpingTouchEventHandler { public SuddenJumpingTouchEventHandler(Context context, ProcessMotionEvent view) { mView = view; - final String[] deviceList = context.getResources().getStringArray( - R.array.sudden_jumping_touch_event_device_list); - mNeedsSuddenJumpingHack = needsSuddenJumpingHack(Build.HARDWARE, deviceList); - } - - private static boolean needsSuddenJumpingHack(String deviceName, String[] deviceList) { - for (String device : deviceList) { - if (device.equalsIgnoreCase(deviceName)) { - return true; - } - } - return false; + mNeedsSuddenJumpingHack = Boolean.parseBoolean(Utils.getDeviceOverrideValue( + context.getResources(), R.array.sudden_jumping_touch_event_device_list, "false")); } public void setKeyboard(Keyboard newKeyboard) { diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 9fc047b75..c1335fdfe 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -19,7 +19,6 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; -import android.os.Build; import android.util.Log; import android.view.inputmethod.EditorInfo; @@ -322,14 +321,8 @@ public class SettingsValues { return volume; } - final String[] volumePerHardwareList = res.getStringArray(R.array.keypress_volumes); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : volumePerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return Float.parseFloat(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1.0f; + return Float.parseFloat( + Utils.getDeviceOverrideValue(res, R.array.keypress_volumes, "-1.0f")); } // Likewise @@ -340,15 +333,9 @@ public class SettingsValues { if (ms >= 0) { return ms; } - final String[] durationPerHardwareList = res.getStringArray( - R.array.keypress_vibration_durations); - final String hardwarePrefix = Build.HARDWARE + ","; - for (final String element : durationPerHardwareList) { - if (element.startsWith(hardwarePrefix)) { - return (int)Long.parseLong(element.substring(element.lastIndexOf(',') + 1)); - } - } - return -1; + + return Integer.parseInt( + Utils.getDeviceOverrideValue(res, R.array.keypress_vibration_durations, "-1")); } // Likewise diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a7de47c58..a914ff76e 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -19,9 +19,11 @@ package com.android.inputmethod.latin; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.net.Uri; import android.os.AsyncTask; +import android.os.Build; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -43,6 +45,7 @@ import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.HashMap; public class Utils { private Utils() { @@ -465,4 +468,23 @@ public class Utils { if (TextUtils.isEmpty(info)) return null; return info; } + + private static final String HARDWARE_PREFIX = Build.HARDWARE + ","; + private static final HashMap sDeviceOverrideValueMap = + new HashMap(); + + public static String getDeviceOverrideValue(Resources res, int overrideResId, String defValue) { + final Integer key = overrideResId; + if (!sDeviceOverrideValueMap.containsKey(key)) { + String overrideValue = defValue; + for (final String element : res.getStringArray(overrideResId)) { + if (element.startsWith(HARDWARE_PREFIX)) { + overrideValue = element.substring(HARDWARE_PREFIX.length()); + break; + } + } + sDeviceOverrideValueMap.put(key, overrideValue); + } + return sDeviceOverrideValueMap.get(key); + } } -- cgit v1.2.3-83-g751a From 78bf41b89c8226870c5ab172d563aa1b16db1513 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Wed, 21 Mar 2012 17:10:19 +0900 Subject: Add additional structure to output logs to group entries by optional fields. The new format has time, time as int, and the new logGroup code (m=motionEvent, k=key, s=statechange, c=correction) followed by additional text whose format depends on the logGroup code. The additional text will be cleaned up in later CL's. 20120321-170548.067+0900 1332317148067 m [Down]143116235,0,691,378,0.40000004,0.435 20120321-170548.133+0900 1332317148133 m [Up]143116302,0,691,378,0.40000004,0.435 20120321-170548.146+0900 1332317148146 k 691 378 20120321-170602.485+0900 1332317162485 s [onStartInputView]com.socialnmobile.dictapps.notepad.color.note,2131624043,147457,1140850694 20120321-170606.508+0900 1332317166508 m [Down]143134679,0,40,154,0.4666667,0.64 20120321-170606.567+0900 1332317166567 m [Move]143134723,0,42,154,0.4666667,0.765 20120321-170606.577+0900 1332317166577 m [Move]143134746,0,44,154,0.4666667,0.775 20120321-170606.652+0900 1332317166652 m [Up]143134824,0,44,154,0.4666667,0.775 20120321-170606.662+0900 1332317166662 k A 40 154 20120321-170607.200+0900 1332317167200 m [Down]143135372,0,411,390,0.53333336,0.585 20120321-170607.311+0900 1332317167311 m [Up]143135483,0,411,390,0.53333336,0.585 20120321-170607.313+0900 1332317167313 c [----]A Bug: 6188932 Change-Id: I8694eb9016d8cf0389ef582f6c7d2820aa4d2c92 --- .../inputmethod/keyboard/LatinKeyboardView.java | 10 ++++---- java/src/com/android/inputmethod/latin/Utils.java | 28 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 9 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index b869059e4..da7d01af4 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -54,6 +54,7 @@ import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeUtils; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; +import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils.LogGroup; import java.util.Locale; import java.util.WeakHashMap; @@ -701,7 +702,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke break; } if (!TextUtils.isEmpty(eventTag)) { - UsabilityStudyLogUtils.getInstance().write( + UsabilityStudyLogUtils.getInstance().write(LogGroup.MOTION_EVENT, eventTag + eventTime + "," + id + "," + x + "," + y + "," + me.getSize(index) + "," + me.getPressure(index)); } @@ -764,9 +765,10 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } tracker.onMoveEvent(px, py, eventTime); if (ENABLE_USABILITY_STUDY_LOG) { - UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + "," - + me.getPointerId(i) + "," + px + "," + py + "," - + me.getSize(i) + "," + me.getPressure(i)); + UsabilityStudyLogUtils.getInstance().write( + LogGroup.MOTION_EVENT, + "[Move]" + eventTime + "," + me.getPointerId(i) + "," + px + "," + py + + "," + me.getSize(i) + "," + me.getPressure(i)); } } } else { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 509bd368d..36a3d3061 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -260,8 +260,25 @@ public class Utils { } } + /** + * Represents a category of logging events that share the same subfield structure. + */ + public static enum LogGroup { + MOTION_EVENT("m"), + KEY("k"), + CORRECTION("c"), + STATE_CHANGE("s"); + + private final String mLogString; + + private LogGroup(String logString) { + mLogString = logString; + } + } + public static void writeBackSpace(int x, int y) { - UsabilityStudyLogUtils.getInstance().write("\t" + x + "\t" + y); + UsabilityStudyLogUtils.getInstance().write( + LogGroup.KEY, "\t" + x + "\t" + y); } public void writeChar(char c, int x, int y) { @@ -277,11 +294,12 @@ public class Utils { inputChar = ""; break; } - UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y); + UsabilityStudyLogUtils.getInstance().write(LogGroup.KEY, + inputChar + "\t" + x + "\t" + y); LatinImeLogger.onPrintAllUsabilityStudyLogs(); } - public void write(final String log) { + public void write(final LogGroup logGroup, final String log) { mLoggingHandler.post(new Runnable() { @Override public void run() { @@ -289,8 +307,8 @@ public class Utils { final long currentTime = System.currentTimeMillis(); mDate.setTime(currentTime); - final String printString = String.format("%s\t%d\t%s\n", - mDateFormat.format(mDate), currentTime, log); + final String printString = String.format("%s\t%d\t%s\t%s\n", + mDateFormat.format(mDate), currentTime, logGroup.mLogString, log); if (LatinImeLogger.sDBG) { Log.d(USABILITY_TAG, "Write: " + log); } -- cgit v1.2.3-83-g751a From fdd68f06579ab338f5d33115aa8300431c75b4fa Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Thu, 22 Mar 2012 11:13:33 +0900 Subject: log through group level abstractions For the groups: - LogGroup.MOTION subfields now deteremined in Utils.writeMotionEvent() rather than in LatinKeyboardView.processMotionEvent() - LogGroup.KEY is now logged throguh LatinIME.onCodeInput() rather than Utils.push(). This catches keys more generally, including modifiers, and records touch positions for everything. Removed now-redundant Utils.writeBackspace() and Utils.writeChar(). - LogGroup.CORRECTION uses Utils.writeCorrection(), and formats instead of leaving this to callers. - LogGroup.STATE_CHANGE uses Utils.writeStateChange(). Optional fields are still left to callers, as this group has more variety. Formats have changed to incorporate new fields. Minor housekeeping: ENABLE_USABILITY_STUDY_LOG constants replaced with variable references, as the logging feature can be changed in Settings and therefore dynamically changes. New log format: 20120322-111203.621+0900 1332382323621 s [onStartInputView] com.socialnmobile.dictapps.notepad.color.note 2131624043 147457 1140850694 20120322-111204.912+0900 1332382324912 m [Down] 2782355 0 243 171 0.5666667 0.895 20120322-111204.975+0900 1332382324975 m [Move] 2782419 0 240 171 0.6 1.17 20120322-111204.983+0900 1332382324983 m [Move] 2782428 0 238 171 0.6 1.1899999 20120322-111204.992+0900 1332382324992 m [Move] 2782437 0 236 171 0.6 1.1899999 20120322-111205.002+0900 1332382325002 m [Move] 2782446 0 232 170 0.6 1.1899999 20120322-111205.012+0900 1332382325012 m [Move] 2782456 0 227 169 0.6 1.125 20120322-111205.021+0900 1332382325021 m [Move] 2782465 0 224 168 0.6 1.125 20120322-111205.031+0900 1332382325031 m [Move] 2782475 0 221 167 0.6 0.895 20120322-111205.040+0900 1332382325040 m [Move] 2782483 0 213 164 0.6 0.58 20120322-111205.047+0900 1332382325047 m [Up] 2782491 0 213 164 0.6 0.58 20120322-111205.052+0900 1332382325052 k 'D' 243 171 20120322-111205.228+0900 1332382325228 m [Down] 2782622 0 171 71 0.6333334 1.275 20120322-111205.243+0900 1332382325243 m [Move] 2782677 0 178 69 0.6333334 1.275 20120322-111205.325+0900 1332382325325 m [Up] 2782750 0 178 69 0.6333334 1.275 20120322-111205.333+0900 1332382325333 k 'e' 171 71 20120322-111205.509+0900 1332382325509 m [Down] 2782936 0 265 139 0.53333336 0.885 20120322-111205.512+0900 1332382325512 m [Move] 2782954 0 265 141 0.53333336 1.04 20120322-111205.552+0900 1332382325552 m [Move] 2782973 0 265 143 0.5666667 1.14 20120322-111205.663+0900 1332382325663 m [Up] 2783102 0 265 143 0.5666667 1.14 20120322-111205.668+0900 1332382325668 k 'f' 265 139 20120322-111206.140+0900 1332382326140 m [Down] 2783584 0 348 352 0.53333336 0.675 20120322-111206.206+0900 1332382326206 m [Move] 2783648 0 348 354 0.5666667 0.73499995 20120322-111206.223+0900 1332382326223 m [Move] 2783666 0 348 356 0.5666667 0.545 20120322-111206.232+0900 1332382326232 m [Up] 2783674 0 348 356 0.5666667 0.545 20120322-111206.236+0900 1332382326236 k ' ' 348 352 20120322-111206.245+0900 1332382326245 c [----] Def -1 Bug: 6188932 Change-Id: Iea46a0c683f858b72005b8e81191ef1d70262dca --- .../inputmethod/keyboard/LatinKeyboardView.java | 45 ++++---------- .../com/android/inputmethod/latin/LatinIME.java | 6 ++ java/src/com/android/inputmethod/latin/Utils.java | 70 +++++++++++++++------- 3 files changed, 64 insertions(+), 57 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index da7d01af4..dca15decd 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -54,7 +54,6 @@ import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeUtils; import com.android.inputmethod.latin.Utils; import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; -import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils.LogGroup; import java.util.Locale; import java.util.WeakHashMap; @@ -70,9 +69,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke SuddenJumpingTouchEventHandler.ProcessMotionEvent { private static final String TAG = LatinKeyboardView.class.getSimpleName(); - // TODO: Kill process when the usability study mode was changed. - private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; - /** Listener for {@link KeyboardActionListener}. */ private KeyboardActionListener mKeyboardActionListener; @@ -672,6 +668,8 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int index = me.getActionIndex(); final int id = me.getPointerId(index); final int x, y; + final float size = me.getSize(index); + final float pressure = me.getPressure(index); if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) { x = mMoreKeysPanel.translateX((int)me.getX(index)); y = mMoreKeysPanel.translateY((int)me.getY(index)); @@ -679,32 +677,11 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke x = (int)me.getX(index); y = (int)me.getY(index); } - if (ENABLE_USABILITY_STUDY_LOG) { - final String eventTag; - switch (action) { - case MotionEvent.ACTION_UP: - eventTag = "[Up]"; - break; - case MotionEvent.ACTION_DOWN: - eventTag = "[Down]"; - break; - case MotionEvent.ACTION_POINTER_UP: - eventTag = "[PointerUp]"; - break; - case MotionEvent.ACTION_POINTER_DOWN: - eventTag = "[PointerDown]"; - break; - case MotionEvent.ACTION_MOVE: // Skip this as being logged below - eventTag = ""; - break; - default: - eventTag = "[Action" + action + "]"; - break; - } - if (!TextUtils.isEmpty(eventTag)) { - UsabilityStudyLogUtils.getInstance().write(LogGroup.MOTION_EVENT, - eventTag + eventTime + "," + id + "," + x + "," + y + "," - + me.getSize(index) + "," + me.getPressure(index)); + if (LatinImeLogger.sUsabilityStudy) { + if (action != MotionEvent.ACTION_MOVE) { + // Skip ACTION_MOVE events as they are logged below + UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id, x, + y, size, pressure); } } @@ -764,11 +741,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke py = (int)me.getY(i); } tracker.onMoveEvent(px, py, eventTime); - if (ENABLE_USABILITY_STUDY_LOG) { - UsabilityStudyLogUtils.getInstance().write( - LogGroup.MOTION_EVENT, - "[Move]" + eventTime + "," + me.getPointerId(i) + "," + px + "," + py - + "," + me.getSize(i) + "," + me.getPressure(i)); + if (LatinImeLogger.sUsabilityStudy) { + UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id, + px, py, size, pressure); } } } else { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index e67f0ea05..48fb79809 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -68,6 +68,7 @@ import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.KeyboardView; import com.android.inputmethod.keyboard.LatinKeyboardView; +import com.android.inputmethod.latin.Utils.UsabilityStudyLogUtils; import com.android.inputmethod.latin.suggestions.SuggestionsView; import java.io.FileDescriptor; @@ -1266,6 +1267,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mDeleteCount = 0; } mLastKeyTime = when; + + if (LatinImeLogger.sUsabilityStudy) { + UsabilityStudyLogUtils.getInstance().writeKeyEvent(primaryCode, x, y); + } + final KeyboardSwitcher switcher = mKeyboardSwitcher; // The space state depends only on the last character pressed and its own previous // state. Here, we revert the space state to neutral if the key is actually modifying diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 36a3d3061..35b4f12a8 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -29,7 +29,9 @@ import android.os.Process; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; +import android.view.MotionEvent; +import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.io.BufferedReader; @@ -135,9 +137,6 @@ public class Utils { // TODO: accept code points public void push(char c, int x, int y) { if (!mEnabled) return; - if (mUsabilityStudy) { - UsabilityStudyLogUtils.getInstance().writeChar(c, x, y); - } mCharBuf[mEnd] = c; mXBuf[mEnd] = x; mYBuf[mEnd] = y; @@ -276,30 +275,57 @@ public class Utils { } } - public static void writeBackSpace(int x, int y) { - UsabilityStudyLogUtils.getInstance().write( - LogGroup.KEY, "\t" + x + "\t" + y); + public void writeMotionEvent(final int action, final long eventTime, final int id, + final int x, final int y, final float size, final float pressure) { + final String eventTag; + switch (action) { + case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break; + case MotionEvent.ACTION_UP: eventTag = "[Up]"; break; + case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break; + case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break; + case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break; + case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break; + case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break; + default: eventTag = "[Action" + action + "]"; break; + } + if (!TextUtils.isEmpty(eventTag)) { + StringBuilder sb = new StringBuilder(); + sb.append(eventTag); + sb.append('\t'); sb.append(eventTime); + sb.append('\t'); sb.append(id); + sb.append('\t'); sb.append(x); + sb.append('\t'); sb.append(y); + sb.append('\t'); sb.append(size); + sb.append('\t'); sb.append(pressure); + write(LogGroup.MOTION_EVENT, sb.toString()); + } } - public void writeChar(char c, int x, int y) { - String inputChar = String.valueOf(c); - switch (c) { - case '\n': - inputChar = ""; - break; - case '\t': - inputChar = ""; - break; - case ' ': - inputChar = ""; - break; - } - UsabilityStudyLogUtils.getInstance().write(LogGroup.KEY, - inputChar + "\t" + x + "\t" + y); + public void writeKeyEvent(int code, int x, int y) { + final StringBuilder sb = new StringBuilder(); + sb.append(Keyboard.printableCode(code)); + sb.append('\t'); sb.append(x); + sb.append('\t'); sb.append(y); + write(LogGroup.KEY, sb.toString()); + + // TODO: replace with a cleaner flush+retrieve mechanism LatinImeLogger.onPrintAllUsabilityStudyLogs(); } - public void write(final LogGroup logGroup, final String log) { + public void writeCorrection(String subgroup, String before, String after, int position) { + final StringBuilder sb = new StringBuilder(); + sb.append(subgroup); + sb.append('\t'); sb.append(before); + sb.append('\t'); sb.append(after); + sb.append('\t'); sb.append(position); + write(LogGroup.CORRECTION, sb.toString()); + } + + public void writeStateChange(String subgroup, String details) { + write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); + } + + private void write(final LogGroup logGroup, final String log) { mLoggingHandler.post(new Runnable() { @Override public void run() { -- cgit v1.2.3-83-g751a From d05afa3f4c59641c8fabed034e457cb25f0c57f0 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Thu, 22 Mar 2012 11:13:33 +0900 Subject: move usability log code to new class (ResearchLogger) and clean api This change also undoes the effects of I8694eb9016, which was an initial effort built on Utils.UsabilityStudyLogs. Now Utils operates as it did previously, for backward compatibility, but the ResearchLogger retains the new log format. Coordinated with I274b75c5. Bug: 6188932 Change-Id: I41208bdc6b511f69a010c9fc38a936521beba7d5 --- .../inputmethod/keyboard/LatinKeyboardView.java | 63 ++++- .../com/android/inputmethod/latin/LatinIME.java | 5 +- .../android/inputmethod/latin/ResearchLogger.java | 302 +++++++++++++++++++++ java/src/com/android/inputmethod/latin/Utils.java | 82 ++---- 4 files changed, 379 insertions(+), 73 deletions(-) create mode 100644 java/src/com/android/inputmethod/latin/ResearchLogger.java (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index b66d1661d..3f6c37477 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.KeySpecParser; import com.android.inputmethod.latin.LatinIME; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; +import com.android.inputmethod.latin.ResearchLogger; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; import com.android.inputmethod.latin.StringUtils; import com.android.inputmethod.latin.SubtypeUtils; @@ -66,6 +67,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke SuddenJumpingTouchEventHandler.ProcessMotionEvent { private static final String TAG = LatinKeyboardView.class.getSimpleName(); + // TODO: Kill process when the usability study mode was changed. + private static final boolean ENABLE_USABILITY_STUDY_LOG = LatinImeLogger.sUsabilityStudy; + /** Listener for {@link KeyboardActionListener}. */ private KeyboardActionListener mKeyboardActionListener; @@ -653,8 +657,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke final int index = me.getActionIndex(); final int id = me.getPointerId(index); final int x, y; - final float size = me.getSize(index); - final float pressure = me.getPressure(index); if (mMoreKeysPanel != null && id == mMoreKeysPanelPointerTrackerId) { x = mMoreKeysPanel.translateX((int)me.getX(index)); y = mMoreKeysPanel.translateY((int)me.getY(index)); @@ -662,10 +664,44 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke x = (int)me.getX(index); y = (int)me.getY(index); } - if (LatinImeLogger.sUsabilityStudy) { + if (ENABLE_USABILITY_STUDY_LOG) { + final String eventTag; + switch (action) { + case MotionEvent.ACTION_UP: + eventTag = "[Up]"; + break; + case MotionEvent.ACTION_DOWN: + eventTag = "[Down]"; + break; + case MotionEvent.ACTION_POINTER_UP: + eventTag = "[PointerUp]"; + break; + case MotionEvent.ACTION_POINTER_DOWN: + eventTag = "[PointerDown]"; + break; + case MotionEvent.ACTION_MOVE: // Skip this as being logged below + eventTag = ""; + break; + default: + eventTag = "[Action" + action + "]"; + break; + } + if (!TextUtils.isEmpty(eventTag)) { + final float size = me.getSize(index); + final float pressure = me.getPressure(index); + UsabilityStudyLogUtils.getInstance().write( + eventTag + eventTime + "," + id + "," + x + "," + y + "," + + size + "," + pressure); + } + } + if (ResearchLogger.sIsLogging) { + // TODO: remove redundant calculations of size and pressure by + // removing UsabilityStudyLog code once the ResearchLogger is mature enough + final float size = me.getSize(index); + final float pressure = me.getPressure(index); if (action != MotionEvent.ACTION_MOVE) { // Skip ACTION_MOVE events as they are logged below - UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id, x, + ResearchLogger.getInstance().logMotionEvent(action, eventTime, id, x, y, size, pressure); } } @@ -714,8 +750,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke if (action == MotionEvent.ACTION_MOVE) { for (int i = 0; i < pointerCount; i++) { + final int pointerId = me.getPointerId(i); final PointerTracker tracker = PointerTracker.getPointerTracker( - me.getPointerId(i), this); + pointerId, this); final int px, py; if (mMoreKeysPanel != null && tracker.mPointerId == mMoreKeysPanelPointerTrackerId) { @@ -726,9 +763,19 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke py = (int)me.getY(i); } tracker.onMoveEvent(px, py, eventTime); - if (LatinImeLogger.sUsabilityStudy) { - UsabilityStudyLogUtils.getInstance().writeMotionEvent(action, eventTime, id, - px, py, size, pressure); + if (ENABLE_USABILITY_STUDY_LOG) { + final float pointerSize = me.getSize(i); + final float pointerPressure = me.getPressure(i); + UsabilityStudyLogUtils.getInstance().write("[Move]" + eventTime + "," + + pointerId + "," + px + "," + py + "," + + pointerSize + "," + pointerPressure); + } + if (ResearchLogger.sIsLogging) { + // TODO: earlier comment about redundant calculations applies here too + final float pointerSize = me.getSize(i); + final float pointerPressure = me.getPressure(i); + ResearchLogger.getInstance().logMotionEvent(action, eventTime, pointerId, + px, py, pointerSize, pointerPressure); } } } else { diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 175d953a6..f5fe8663e 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -439,6 +439,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); mPrefs = prefs; LatinImeLogger.init(this, prefs); + ResearchLogger.init(this, prefs); LanguageSwitcherProxy.init(this, prefs); InputMethodManagerCompatWrapper.init(this); SubtypeSwitcher.init(this); @@ -1263,8 +1264,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } mLastKeyTime = when; - if (LatinImeLogger.sUsabilityStudy) { - UsabilityStudyLogUtils.getInstance().writeKeyEvent(primaryCode, x, y); + if (ResearchLogger.sIsLogging) { + ResearchLogger.getInstance().logKeyEvent(primaryCode, x, y); } final KeyboardSwitcher switcher = mKeyboardSwitcher; diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java new file mode 100644 index 000000000..509fbe0fd --- /dev/null +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2012 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.SharedPreferences; +import android.inputmethodservice.InputMethodService; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Process; +import android.text.TextUtils; +import android.util.Log; +import android.view.MotionEvent; + +import com.android.inputmethod.keyboard.Keyboard; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Logs the use of the LatinIME keyboard. + * + * This class logs operations on the IME keyboard, including what the user has typed. + * Data is stored locally in a file in app-specific storage. + * + * This functionality is off by default. + */ +public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { + private static final String TAG = ResearchLogger.class.getSimpleName(); + private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; + + private static final ResearchLogger sInstance = new ResearchLogger(new LogFileManager()); + public static boolean sIsLogging = false; + private final Handler mLoggingHandler; + private InputMethodService mIms; + private final Date mDate; + private final SimpleDateFormat mDateFormat; + + /** + * Isolates management of files. This variable should never be null, but can be changed + * to support testing. + */ + private LogFileManager mLogFileManager; + + /** + * Manages the file(s) that stores the logs. + * + * Handles creation, deletion, and provides Readers, Writers, and InputStreams to access + * the logs. + */ + public static class LogFileManager { + private static final String DEFAULT_FILENAME = "log.txt"; + private static final String DEFAULT_LOG_DIRECTORY = "researchLogger"; + + private static final long LOGFILE_PURGE_INTERVAL = 1000 * 60 * 60 * 24; + + private InputMethodService mIms; + private File mFile; + private PrintWriter mPrintWriter; + + /* package */ LogFileManager() { + } + + public void init(InputMethodService ims) { + mIms = ims; + } + + public synchronized void createLogFile() { + try { + createLogFile(DEFAULT_LOG_DIRECTORY, DEFAULT_FILENAME); + } catch (FileNotFoundException e) { + Log.w(TAG, e); + } + } + + public synchronized void createLogFile(String dir, String filename) + throws FileNotFoundException { + if (mIms == null) { + Log.w(TAG, "InputMethodService is not configured. Logging is off."); + return; + } + File filesDir = mIms.getFilesDir(); + if (filesDir == null || !filesDir.exists()) { + Log.w(TAG, "Storage directory does not exist. Logging is off."); + return; + } + File directory = new File(filesDir, dir); + if (!directory.exists()) { + boolean wasCreated = directory.mkdirs(); + if (!wasCreated) { + Log.w(TAG, "Log directory cannot be created. Logging is off."); + return; + } + } + + close(); + mFile = new File(directory, filename); + boolean append = true; + if (mFile.exists() && mFile.lastModified() + LOGFILE_PURGE_INTERVAL < + System.currentTimeMillis()) { + append = false; + } + mPrintWriter = new PrintWriter(new FileOutputStream(mFile, append), true); + } + + public synchronized boolean append(String s) { + if (mPrintWriter == null) { + Log.w(TAG, "PrintWriter is null"); + return false; + } else { + mPrintWriter.print(s); + return !mPrintWriter.checkError(); + } + } + + public synchronized void reset() { + if (mPrintWriter != null) { + mPrintWriter.close(); + mPrintWriter = null; + } + if (mFile != null && mFile.exists()) { + mFile.delete(); + mFile = null; + } + } + + public synchronized void close() { + if (mPrintWriter != null) { + mPrintWriter.close(); + mPrintWriter = null; + mFile = null; + } + } + } + + private ResearchLogger(LogFileManager logFileManager) { + mDate = new Date(); + mDateFormat = new SimpleDateFormat("yyyyMMdd-HHmmss.SSSZ"); + + HandlerThread handlerThread = new HandlerThread("ResearchLogger logging task", + Process.THREAD_PRIORITY_BACKGROUND); + handlerThread.start(); + mLoggingHandler = new Handler(handlerThread.getLooper()); + mLogFileManager = logFileManager; + } + + public static ResearchLogger getInstance() { + return sInstance; + } + + public static void init(InputMethodService ims, SharedPreferences prefs) { + sInstance.initInternal(ims, prefs); + } + + public void initInternal(InputMethodService ims, SharedPreferences prefs) { + mIms = ims; + if (mLogFileManager != null) { + mLogFileManager.init(ims); + mLogFileManager.createLogFile(); + } + if (prefs != null) { + sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); + } + prefs.registerOnSharedPreferenceChangeListener(this); + } + + /** + * Change to a different logFileManager. Will not allow it to be set to null. + */ + /* package */ void setLogFileManager(ResearchLogger.LogFileManager manager) { + if (manager == null) { + Log.w(TAG, "warning: trying to set null logFileManager. ignoring."); + } else { + mLogFileManager = manager; + } + } + + /** + * Represents a category of logging events that share the same subfield structure. + */ + private static enum LogGroup { + MOTION_EVENT("m"), + KEY("k"), + CORRECTION("c"), + STATE_CHANGE("s"); + + private final String mLogString; + + private LogGroup(String logString) { + mLogString = logString; + } + } + + public void logMotionEvent(final int action, final long eventTime, final int id, + final int x, final int y, final float size, final float pressure) { + final String eventTag; + switch (action) { + case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break; + case MotionEvent.ACTION_UP: eventTag = "[Up]"; break; + case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break; + case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break; + case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break; + case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break; + case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break; + default: eventTag = "[Action" + action + "]"; break; + } + if (!TextUtils.isEmpty(eventTag)) { + StringBuilder sb = new StringBuilder(); + sb.append(eventTag); + sb.append('\t'); sb.append(eventTime); + sb.append('\t'); sb.append(id); + sb.append('\t'); sb.append(x); + sb.append('\t'); sb.append(y); + sb.append('\t'); sb.append(size); + sb.append('\t'); sb.append(pressure); + write(LogGroup.MOTION_EVENT, sb.toString()); + } + } + + public void logKeyEvent(int code, int x, int y) { + final StringBuilder sb = new StringBuilder(); + sb.append(Keyboard.printableCode(code)); + sb.append('\t'); sb.append(x); + sb.append('\t'); sb.append(y); + write(LogGroup.KEY, sb.toString()); + + LatinImeLogger.onPrintAllUsabilityStudyLogs(); + } + + public void logCorrection(String subgroup, String before, String after, int position) { + final StringBuilder sb = new StringBuilder(); + sb.append(subgroup); + sb.append('\t'); sb.append(before); + sb.append('\t'); sb.append(after); + sb.append('\t'); sb.append(position); + write(LogGroup.CORRECTION, sb.toString()); + } + + public void logStateChange(String subgroup, String details) { + write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); + } + + private void write(final LogGroup logGroup, final String log) { + mLoggingHandler.post(new Runnable() { + @Override + public void run() { + final long currentTime = System.currentTimeMillis(); + mDate.setTime(currentTime); + + final String printString = String.format("%s\t%d\t%s\t%s\n", + mDateFormat.format(mDate), currentTime, logGroup.mLogString, log); + if (LatinImeLogger.sDBG) { + Log.d(TAG, "Write: " + '[' + logGroup.mLogString + ']' + log); + } + if (mLogFileManager.append(printString)) { + // success + } else { + if (LatinImeLogger.sDBG) { + Log.w(TAG, "Unable to write to log."); + } + } + } + }); + } + + public void clearAll() { + mLoggingHandler.post(new Runnable() { + @Override + public void run() { + if (LatinImeLogger.sDBG) { + Log.d(TAG, "Delete log file."); + } + mLogFileManager.reset(); + } + }); + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if (key == null || prefs == null) { + return; + } + sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); + } +} diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a3589da0a..be64c2fd8 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -220,6 +220,7 @@ public class Utils { } public static class UsabilityStudyLogUtils { + // TODO: remove code duplication with ResearchLog class private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName(); private static final String FILENAME = "log.txt"; private static final UsabilityStudyLogUtils sInstance = @@ -262,73 +263,28 @@ public class Utils { } } - /** - * Represents a category of logging events that share the same subfield structure. - */ - public static enum LogGroup { - MOTION_EVENT("m"), - KEY("k"), - CORRECTION("c"), - STATE_CHANGE("s"); - - private final String mLogString; - - private LogGroup(String logString) { - mLogString = logString; - } + public static void writeBackSpace(int x, int y) { + UsabilityStudyLogUtils.getInstance().write("\t" + x + "\t" + y); } - public void writeMotionEvent(final int action, final long eventTime, final int id, - final int x, final int y, final float size, final float pressure) { - final String eventTag; - switch (action) { - case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break; - case MotionEvent.ACTION_UP: eventTag = "[Up]"; break; - case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break; - case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break; - case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break; - case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break; - case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break; - default: eventTag = "[Action" + action + "]"; break; - } - if (!TextUtils.isEmpty(eventTag)) { - StringBuilder sb = new StringBuilder(); - sb.append(eventTag); - sb.append('\t'); sb.append(eventTime); - sb.append('\t'); sb.append(id); - sb.append('\t'); sb.append(x); - sb.append('\t'); sb.append(y); - sb.append('\t'); sb.append(size); - sb.append('\t'); sb.append(pressure); - write(LogGroup.MOTION_EVENT, sb.toString()); + public void writeChar(char c, int x, int y) { + String inputChar = String.valueOf(c); + switch (c) { + case '\n': + inputChar = ""; + break; + case '\t': + inputChar = ""; + break; + case ' ': + inputChar = ""; + break; } - } - - public void writeKeyEvent(int code, int x, int y) { - final StringBuilder sb = new StringBuilder(); - sb.append(Keyboard.printableCode(code)); - sb.append('\t'); sb.append(x); - sb.append('\t'); sb.append(y); - write(LogGroup.KEY, sb.toString()); - - // TODO: replace with a cleaner flush+retrieve mechanism + UsabilityStudyLogUtils.getInstance().write(inputChar + "\t" + x + "\t" + y); LatinImeLogger.onPrintAllUsabilityStudyLogs(); } - public void writeCorrection(String subgroup, String before, String after, int position) { - final StringBuilder sb = new StringBuilder(); - sb.append(subgroup); - sb.append('\t'); sb.append(before); - sb.append('\t'); sb.append(after); - sb.append('\t'); sb.append(position); - write(LogGroup.CORRECTION, sb.toString()); - } - - public void writeStateChange(String subgroup, String details) { - write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); - } - - private void write(final LogGroup logGroup, final String log) { + public void write(final String log) { mLoggingHandler.post(new Runnable() { @Override public void run() { @@ -336,8 +292,8 @@ public class Utils { final long currentTime = System.currentTimeMillis(); mDate.setTime(currentTime); - final String printString = String.format("%s\t%d\t%s\t%s\n", - mDateFormat.format(mDate), currentTime, logGroup.mLogString, log); + final String printString = String.format("%s\t%d\t%s\n", + mDateFormat.format(mDate), currentTime, log); if (LatinImeLogger.sDBG) { Log.d(USABILITY_TAG, "Write: " + log); } -- cgit v1.2.3-83-g751a From 356776a9b7150d2485b340ac7f9daaef090c1f69 Mon Sep 17 00:00:00 2001 From: satok Date: Mon, 26 Mar 2012 17:43:38 +0900 Subject: Put a misspelled flag if the word is not valid by the same logic of Android spell checker. Bug: 6222722 Currently, the flags of the suggestion span from the Latin IME is different from the flags from Android spell checker. Change-Id: I2f7a54ae0d63235a0b94e039109ab8b2f1311055 --- .../inputmethod/compat/SuggestionSpanUtils.java | 32 +++++++++++++++++----- java/src/com/android/inputmethod/latin/Utils.java | 4 --- 2 files changed, 25 insertions(+), 11 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java index e82d91411..a9e48404a 100644 --- a/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java +++ b/java/src/com/android/inputmethod/compat/SuggestionSpanUtils.java @@ -48,21 +48,30 @@ public class SuggestionSpanUtils { Context.class, Locale.class, String[].class, int.class, Class.class }; private static final Constructor CONSTRUCTOR_SuggestionSpan = CompatUtils .getConstructor(CLASS_SuggestionSpan, INPUT_TYPE_SuggestionSpan); - public static final Field FIELD_FLAG_AUTO_CORRECTION - = CompatUtils.getField(CLASS_SuggestionSpan, "FLAG_AUTO_CORRECTION"); + public static final Field FIELD_FLAG_EASY_CORRECT = + CompatUtils.getField(CLASS_SuggestionSpan, "FLAG_EASY_CORRECT"); + public static final Field FIELD_FLAG_MISSPELLED = + CompatUtils.getField(CLASS_SuggestionSpan, "FLAG_MISSPELLED"); + public static final Field FIELD_FLAG_AUTO_CORRECTION = + CompatUtils.getField(CLASS_SuggestionSpan, "FLAG_AUTO_CORRECTION"); public static final Field FIELD_SUGGESTIONS_MAX_SIZE = CompatUtils.getField(CLASS_SuggestionSpan, "SUGGESTIONS_MAX_SIZE"); + public static final Integer OBJ_FLAG_EASY_CORRECT = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_FLAG_EASY_CORRECT); + public static final Integer OBJ_FLAG_MISSPELLED = (Integer) CompatUtils + .getFieldValue(null, null, FIELD_FLAG_MISSPELLED); public static final Integer OBJ_FLAG_AUTO_CORRECTION = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_FLAG_AUTO_CORRECTION);; + .getFieldValue(null, null, FIELD_FLAG_AUTO_CORRECTION); public static final Integer OBJ_SUGGESTIONS_MAX_SIZE = (Integer) CompatUtils - .getFieldValue(null, null, FIELD_SUGGESTIONS_MAX_SIZE);; + .getFieldValue(null, null, FIELD_SUGGESTIONS_MAX_SIZE); static { SUGGESTION_SPAN_IS_SUPPORTED = CLASS_SuggestionSpan != null && CONSTRUCTOR_SuggestionSpan != null; if (LatinImeLogger.sDBG) { if (SUGGESTION_SPAN_IS_SUPPORTED - && (OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null)) { + && (OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null + || OBJ_FLAG_MISSPELLED == null || OBJ_FLAG_EASY_CORRECT == null)) { throw new RuntimeException("Field is accidentially null."); } } @@ -71,7 +80,8 @@ public class SuggestionSpanUtils { public static CharSequence getTextWithAutoCorrectionIndicatorUnderline( Context context, CharSequence text) { if (TextUtils.isEmpty(text) || CONSTRUCTOR_SuggestionSpan == null - || OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null) { + || OBJ_FLAG_AUTO_CORRECTION == null || OBJ_SUGGESTIONS_MAX_SIZE == null + || OBJ_FLAG_MISSPELLED == null || OBJ_FLAG_EASY_CORRECT == null) { return text; } final Spannable spannable = text instanceof Spannable @@ -104,6 +114,7 @@ public class SuggestionSpanUtils { spannable = new SpannableString(pickedWord); } final ArrayList suggestionsList = new ArrayList(); + boolean sameAsTyped = false; for (int i = 0; i < suggestedWords.size(); ++i) { if (suggestionsList.size() >= OBJ_SUGGESTIONS_MAX_SIZE) { break; @@ -111,11 +122,18 @@ public class SuggestionSpanUtils { final CharSequence word = suggestedWords.getWord(i); if (!TextUtils.equals(pickedWord, word)) { suggestionsList.add(word.toString()); + } else if (i == 0) { + sameAsTyped = true; } } + // TODO: Share the implementation for checking typed word validity between the IME + // and the spell checker. + final int flag = (sameAsTyped && !suggestedWords.mTypedWordValid) + ? ((int)OBJ_FLAG_EASY_CORRECT | (int)OBJ_FLAG_MISSPELLED) + : 0; final Object[] args = - { context, null, suggestionsList.toArray(new String[suggestionsList.size()]), 0, + { context, null, suggestionsList.toArray(new String[suggestionsList.size()]), flag, (Class) SuggestionSpanPickedNotificationReceiver.class }; final Object ss = CompatUtils.newInstance(CONSTRUCTOR_SuggestionSpan, args); if (ss == null) { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index be64c2fd8..0485c881b 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -31,9 +31,7 @@ import android.os.Process; import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; -import android.view.MotionEvent; -import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.io.BufferedReader; @@ -112,7 +110,6 @@ public class Utils { /* package */ static final int BUFSIZE = 20; private InputMethodService mContext; private boolean mEnabled = false; - private boolean mUsabilityStudy = false; private int mEnd = 0; /* package */ int mLength = 0; private char[] mCharBuf = new char[BUFSIZE]; @@ -129,7 +126,6 @@ public class Utils { boolean usabilityStudy) { sRingCharBuffer.mContext = context; sRingCharBuffer.mEnabled = enabled || usabilityStudy; - sRingCharBuffer.mUsabilityStudy = usabilityStudy; UsabilityStudyLogUtils.getInstance().init(context); return sRingCharBuffer; } -- cgit v1.2.3-83-g751a From 11a40a047fc0e72e0ad4cc6743e37e96b1bc0e7a Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Mon, 16 Apr 2012 12:59:55 +0900 Subject: Make Utils.getDeviceOverrideValue aware of device orientation Bug: 6277225 Change-Id: If41fe5cbee0985b9a4740dcd5d1c6ba73b94b377 --- java/src/com/android/inputmethod/latin/Utils.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 0485c881b..036ff74b8 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -466,11 +466,12 @@ public class Utils { } private static final String HARDWARE_PREFIX = Build.HARDWARE + ","; - private static final HashMap sDeviceOverrideValueMap = - new HashMap(); + private static final HashMap sDeviceOverrideValueMap = + new HashMap(); public static String getDeviceOverrideValue(Resources res, int overrideResId, String defValue) { - final Integer key = overrideResId; + final int orientation = res.getConfiguration().orientation; + final String key = overrideResId + "-" + orientation; if (!sDeviceOverrideValueMap.containsKey(key)) { String overrideValue = defValue; for (final String element : res.getStringArray(overrideResId)) { -- cgit v1.2.3-83-g751a From fd53b8cc2b78acd7e33f4dc39cfc2faaea92f0f8 Mon Sep 17 00:00:00 2001 From: satok Date: Fri, 18 May 2012 21:28:09 +0900 Subject: Forget user history Bug: 4192129 Change-Id: Ic98398e5383093a1c24373849eadc48fc4d3626f --- .../inputmethod/latin/ContactsDictionary.java | 2 +- .../inputmethod/latin/ExpandableDictionary.java | 136 ++++++++++++++----- .../com/android/inputmethod/latin/LatinIME.java | 3 +- .../com/android/inputmethod/latin/Settings.java | 3 +- .../android/inputmethod/latin/SettingsValues.java | 21 +++ .../inputmethod/latin/UserHistoryDictionary.java | 148 +++++++++++++-------- .../latin/UserHistoryForgettingCurveUtils.java | 82 +++++++++++- java/src/com/android/inputmethod/latin/Utils.java | 38 ++++++ 8 files changed, 333 insertions(+), 100 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/ContactsDictionary.java b/java/src/com/android/inputmethod/latin/ContactsDictionary.java index c9b8d6eb1..cbfbd0ec8 100644 --- a/java/src/com/android/inputmethod/latin/ContactsDictionary.java +++ b/java/src/com/android/inputmethod/latin/ContactsDictionary.java @@ -159,7 +159,7 @@ public class ContactsDictionary extends ExpandableDictionary { super.addWord(word, null /* shortcut */, FREQUENCY_FOR_CONTACTS); if (!TextUtils.isEmpty(prevWord)) { - super.setBigram(prevWord, word, + super.setBigramAndGetFrequency(prevWord, word, FREQUENCY_FOR_CONTACTS_BIGRAM); } prevWord = word; diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 6c457afd2..358cd4d4d 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -21,6 +21,7 @@ import android.content.Context; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; import java.util.ArrayList; import java.util.LinkedList; @@ -80,31 +81,73 @@ public class ExpandableDictionary extends Dictionary { } } - private static class NextWord { - public final Node mWord; - private int mFrequency; + protected interface NextWord { + public Node getWordNode(); + public int getFrequency(); + /** FcValue is a bit set */ + public int getFcValue(); + public int notifyTypedAgainAndGetFrequency(); + } - public NextWord(Node word, int frequency) { + private static class NextStaticWord implements NextWord { + public final Node mWord; + private final int mFrequency; + public NextStaticWord(Node word, int frequency) { mWord = word; mFrequency = frequency; } + @Override + public Node getWordNode() { + return mWord; + } + + @Override public int getFrequency() { return mFrequency; } - public int setFrequency(int freq) { - mFrequency = freq; + @Override + public int getFcValue() { return mFrequency; } - public int addFrequency(int add) { - mFrequency += add; - if (mFrequency > BIGRAM_MAX_FREQUENCY) mFrequency = BIGRAM_MAX_FREQUENCY; + @Override + public int notifyTypedAgainAndGetFrequency() { return mFrequency; } } + private static class NextHistoryWord implements NextWord { + public final Node mWord; + public final ForgettingCurveParams mFcp; + + public NextHistoryWord(Node word, ForgettingCurveParams fcp) { + mWord = word; + mFcp = fcp; + } + + @Override + public Node getWordNode() { + return mWord; + } + + @Override + public int getFrequency() { + return mFcp.getFrequency(); + } + + @Override + public int getFcValue() { + return mFcp.getFc(); + } + + @Override + public int notifyTypedAgainAndGetFrequency() { + return mFcp.notifyTypedAgainAndGetFrequency(); + } + } + private NodeArray mRoots; private int[][] mCodes; @@ -183,7 +226,7 @@ public class ExpandableDictionary extends Dictionary { childNode.mShortcutOnly = isShortcutOnly; children.add(childNode); } - if (wordLength == depth + 1) { + if (wordLength == depth + 1 && shortcutTarget != null) { // Terminate this word childNode.mTerminal = true; if (isShortcutOnly) { @@ -221,7 +264,7 @@ public class ExpandableDictionary extends Dictionary { protected final void getWordsInner(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, - @SuppressWarnings("unused") final ProximityInfo proximityInfo) { + final ProximityInfo proximityInfo) { mInputLength = codes.size(); if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; final int[] xCoordinates = codes.getXCoordinates(); @@ -265,13 +308,13 @@ public class ExpandableDictionary extends Dictionary { // Refer to addOrSetBigram() about word1.toLowerCase() final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); final Node secondWord = searchWord(mRoots, word2, 0, null); - LinkedList bigram = firstWord.mNGrams; + LinkedList bigrams = firstWord.mNGrams; NextWord bigramNode = null; - if (bigram == null || bigram.size() == 0) { + if (bigrams == null || bigrams.size() == 0) { return false; } else { - for (NextWord nw : bigram) { - if (nw.mWord == secondWord) { + for (NextWord nw : bigrams) { + if (nw.getWordNode() == secondWord) { bigramNode = nw; break; } @@ -280,7 +323,7 @@ public class ExpandableDictionary extends Dictionary { if (bigramNode == null) { return false; } - return bigram.remove(bigramNode); + return bigrams.remove(bigramNode); } /** @@ -292,6 +335,23 @@ public class ExpandableDictionary extends Dictionary { return (node == null) ? -1 : node.mFrequency; } + protected NextWord getBigramWord(String word1, String word2) { + // Refer to addOrSetBigram() about word1.toLowerCase() + final Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); + final Node secondWord = searchWord(mRoots, word2, 0, null); + LinkedList bigrams = firstWord.mNGrams; + if (bigrams == null || bigrams.size() == 0) { + return null; + } else { + for (NextWord nw : bigrams) { + if (nw.getWordNode() == secondWord) { + return nw; + } + } + } + return null; + } + private static int computeSkippedWordFinalFreq(int freq, int snr, int inputLength) { // The computation itself makes sense for >= 2, but the == 2 case returns 0 // anyway so we may as well test against 3 instead and return the constant @@ -445,43 +505,45 @@ public class ExpandableDictionary extends Dictionary { } } - protected int setBigram(String word1, String word2, int frequency) { - return addOrSetBigram(word1, word2, frequency, false); + public int setBigramAndGetFrequency(String word1, String word2, int frequency) { + return setBigramAndGetFrequency(word1, word2, frequency, null /* unused */); } - protected int addBigram(String word1, String word2, int frequency) { - return addOrSetBigram(word1, word2, frequency, true); + public int setBigramAndGetFrequency(String word1, String word2, ForgettingCurveParams fcp) { + return setBigramAndGetFrequency(word1, word2, 0 /* unused */, fcp); } /** * Adds bigrams to the in-memory trie structure that is being used to retrieve any word * @param frequency frequency for this bigram * @param addFrequency if true, it adds to current frequency, else it overwrites the old value - * @return returns the final frequency + * @return returns the final bigram frequency */ - private int addOrSetBigram(String word1, String word2, int frequency, boolean addFrequency) { + private int setBigramAndGetFrequency( + String word1, String word2, int frequency, ForgettingCurveParams fcp) { // We don't want results to be different according to case of the looked up left hand side // word. We do want however to return the correct case for the right hand side. // So we want to squash the case of the left hand side, and preserve that of the right // hand side word. Node firstWord = searchWord(mRoots, word1.toLowerCase(), 0, null); Node secondWord = searchWord(mRoots, word2, 0, null); - LinkedList bigram = firstWord.mNGrams; - if (bigram == null || bigram.size() == 0) { + LinkedList bigrams = firstWord.mNGrams; + if (bigrams == null || bigrams.size() == 0) { firstWord.mNGrams = new LinkedList(); - bigram = firstWord.mNGrams; + bigrams = firstWord.mNGrams; } else { - for (NextWord nw : bigram) { - if (nw.mWord == secondWord) { - if (addFrequency) { - return nw.addFrequency(frequency); - } else { - return nw.setFrequency(frequency); - } + for (NextWord nw : bigrams) { + if (nw.getWordNode() == secondWord) { + return nw.notifyTypedAgainAndGetFrequency(); } } } - firstWord.mNGrams.add(new NextWord(secondWord, frequency)); + if (fcp != null) { + // history + firstWord.mNGrams.add(new NextHistoryWord(secondWord, fcp)); + } else { + firstWord.mNGrams.add(new NextStaticWord(secondWord, frequency)); + } return frequency; } @@ -580,7 +642,7 @@ public class ExpandableDictionary extends Dictionary { Node node; int freq; for (NextWord nextWord : terminalNodes) { - node = nextWord.mWord; + node = nextWord.getWordNode(); freq = nextWord.getFrequency(); int index = BinaryDictionary.MAX_WORD_LENGTH; do { @@ -589,8 +651,10 @@ public class ExpandableDictionary extends Dictionary { node = node.mParent; } while (node != null); - callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index, - freq, mDicTypeId, Dictionary.BIGRAM); + if (freq >= 0) { + callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index, + freq, mDicTypeId, Dictionary.BIGRAM); + } } } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index c58549497..e9117e29a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -494,7 +494,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen resetContactsDictionary(oldContactsDictionary); mUserHistoryDictionary = new UserHistoryDictionary( - this, localeStr, Suggest.DIC_USER_HISTORY); + this, localeStr, Suggest.DIC_USER_HISTORY, mPrefs); mSuggest.setUserHistoryDictionary(mUserHistoryDictionary); } @@ -745,7 +745,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen KeyboardView inputView = mKeyboardSwitcher.getKeyboardView(); if (inputView != null) inputView.closing(); - if (mUserHistoryDictionary != null) mUserHistoryDictionary.flushPendingWrites(); } private void onFinishInputViewInternal(boolean finishingInput) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 74c4aea0c..08f3e8456 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -58,6 +58,8 @@ public class Settings extends InputMethodSettingsFragment public static final String PREF_SHOW_SUGGESTIONS_SETTING = "show_suggestions_setting"; public static final String PREF_MISC_SETTINGS = "misc_settings"; public static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; + public static final String PREF_LAST_USER_DICTIONARY_WRITE_TIME = + "last_user_dictionary_write_time"; public static final String PREF_ADVANCED_SETTINGS = "pref_advanced_settings"; public static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = "pref_suppress_language_switch_key"; @@ -244,7 +246,6 @@ public class Settings extends InputMethodSettingsFragment refreshEnablingsOfKeypressSoundAndVibrationSettings(prefs, res); } - @SuppressWarnings("unused") @Override public void onResume() { super.onResume(); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 932920a60..4aae6a85e 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -28,6 +28,8 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; /** * When you call the constructor of this class, you may want to change the current system locale by @@ -351,4 +353,23 @@ public class SettingsValues { // TODO: use mUsabilityStudyMode instead of reading it again here return prefs.getBoolean(Settings.PREF_USABILITY_STUDY_MODE, true); } + + public static long getLastUserHistoryWriteTime( + final SharedPreferences prefs, final String locale) { + final String str = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap map = Utils.localeAndTimeStrToHashMap(str); + if (map.containsKey(locale)) { + return map.get(locale); + } + return 0; + } + + public static void setLastUserHistoryWriteTime( + final SharedPreferences prefs, final String locale) { + final String oldStr = prefs.getString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, ""); + final HashMap map = Utils.localeAndTimeStrToHashMap(oldStr); + map.put(locale, System.currentTimeMillis()); + final String newStr = Utils.localeAndTimeHashMapToStr(map); + prefs.edit().putString(Settings.PREF_LAST_USER_DICTIONARY_WRITE_TIME, newStr).apply(); + } } diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index efafacc8a..fa3d1be11 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.content.ContentValues; import android.content.Context; +import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; @@ -26,6 +27,8 @@ import android.os.AsyncTask; import android.provider.BaseColumns; import android.util.Log; +import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; + import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -40,9 +43,6 @@ public class UserHistoryDictionary extends ExpandableDictionary { /** Any pair being typed or picked */ private static final int FREQUENCY_FOR_TYPED = 2; - /** Maximum frequency for all pairs */ - private static final int FREQUENCY_MAX = 127; - /** Maximum number of pairs. Pruning will start when databases goes above this number. */ private static int sMaxHistoryBigrams = 10000; @@ -81,6 +81,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { private HashSet mPendingWrites = new HashSet(); private final Object mPendingWritesLock = new Object(); private static volatile boolean sUpdatingDB = false; + private final SharedPreferences mPrefs; private final static HashMap sDictProjectionMap; @@ -101,12 +102,10 @@ public class UserHistoryDictionary extends ExpandableDictionary { private static class Bigram { public final String mWord1; public final String mWord2; - public final int mFrequency; - Bigram(String word1, String word2, int frequency) { + Bigram(String word1, String word2) { this.mWord1 = word1; this.mWord2 = word2; - this.mFrequency = frequency; } @Override @@ -137,7 +136,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { sDeleteHistoryBigrams = deleteHistoryBigram; } - public UserHistoryDictionary(final Context context, final String locale, final int dicTypeId) { + public UserHistoryDictionary(final Context context, final String locale, final int dicTypeId, + SharedPreferences sp) { super(context, dicTypeId); mLocale = locale; if (sOpenHelper == null) { @@ -146,11 +146,13 @@ public class UserHistoryDictionary extends ExpandableDictionary { if (mLocale != null && mLocale.length() > 1) { loadDictionary(); } + mPrefs = sp; } @Override public void close() { flushPendingWrites(); + SettingsValues.setLastUserHistoryWriteTime(mPrefs, mLocale); // Don't close the database as locale changes will require it to be reopened anyway // Also, the database is written to somewhat frequently, so it needs to be kept alive // throughout the life of the process. @@ -176,25 +178,20 @@ public class UserHistoryDictionary extends ExpandableDictionary { * The second word may not be null (a NullPointerException would be thrown). */ public int addToUserHistory(final String word1, String word2) { - super.addWord(word2, null /* shortcut */, FREQUENCY_FOR_TYPED); + super.addWord(word2, null /* the "shortcut" parameter is null */, FREQUENCY_FOR_TYPED); // Do not insert a word as a bigram of itself if (word2.equals(word1)) { return 0; } - - int freq; + final int freq; if (null == word1) { freq = FREQUENCY_FOR_TYPED; } else { - freq = super.addBigram(word1, word2, FREQUENCY_FOR_TYPED); + freq = super.setBigramAndGetFrequency(word1, word2, new ForgettingCurveParams()); } - if (freq > FREQUENCY_MAX) freq = FREQUENCY_MAX; synchronized (mPendingWritesLock) { - if (freq == FREQUENCY_FOR_TYPED || mPendingWrites.isEmpty()) { - mPendingWrites.add(new Bigram(word1, word2, freq)); - } else { - Bigram bi = new Bigram(word1, word2, freq); - mPendingWrites.remove(bi); + final Bigram bi = new Bigram(word1, word2); + if (!mPendingWrites.contains(bi)) { mPendingWrites.add(bi); } } @@ -203,7 +200,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { } public boolean cancelAddingUserHistory(String word1, String word2) { - final Bigram bi = new Bigram(word1, word2, 0); + final Bigram bi = new Bigram(word1, word2); if (mPendingWrites.contains(bi)) { mPendingWrites.remove(bi); return super.removeBigram(word1, word2); @@ -214,12 +211,12 @@ public class UserHistoryDictionary extends ExpandableDictionary { /** * Schedules a background thread to write any pending words to the database. */ - public void flushPendingWrites() { + private void flushPendingWrites() { synchronized (mPendingWritesLock) { // Nothing pending? Return if (mPendingWrites.isEmpty()) return; // Create a background thread to write the pending entries - new UpdateDbTask(sOpenHelper, mPendingWrites, mLocale).execute(); + new UpdateDbTask(sOpenHelper, mPendingWrites, mLocale, this).execute(); // Create a new map for writing new entries into while the old one is written to db mPendingWrites = new HashSet(); } @@ -240,25 +237,30 @@ public class UserHistoryDictionary extends ExpandableDictionary { @Override public void loadDictionaryAsync() { + final long last = SettingsValues.getLastUserHistoryWriteTime(mPrefs, mLocale); + final long now = System.currentTimeMillis(); // Load the words that correspond to the current input locale final Cursor cursor = query(MAIN_COLUMN_LOCALE + "=?", new String[] { mLocale }); if (null == cursor) return; try { if (cursor.moveToFirst()) { - int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1); - int word2Index = cursor.getColumnIndex(MAIN_COLUMN_WORD2); - int frequencyIndex = cursor.getColumnIndex(FREQ_COLUMN_FREQUENCY); + final int word1Index = cursor.getColumnIndex(MAIN_COLUMN_WORD1); + final int word2Index = cursor.getColumnIndex(MAIN_COLUMN_WORD2); + final int frequencyIndex = cursor.getColumnIndex(FREQ_COLUMN_FREQUENCY); while (!cursor.isAfterLast()) { - String word1 = cursor.getString(word1Index); - String word2 = cursor.getString(word2Index); - int frequency = cursor.getInt(frequencyIndex); + final String word1 = cursor.getString(word1Index); + final String word2 = cursor.getString(word2Index); + final int frequency = cursor.getInt(frequencyIndex); // Safeguard against adding really long words. Stack may overflow due // to recursive lookup if (null == word1) { super.addWord(word2, null /* shortcut */, frequency); } else if (word1.length() < BinaryDictionary.MAX_WORD_LENGTH && word2.length() < BinaryDictionary.MAX_WORD_LENGTH) { - super.setBigram(word1, word2, frequency); + super.setBigramAndGetFrequency( + word1, word2, new ForgettingCurveParams(frequency, now, last)); + // TODO: optimize + mPendingWrites.add(new Bigram(word1, word2)); } cursor.moveToNext(); } @@ -340,12 +342,14 @@ public class UserHistoryDictionary extends ExpandableDictionary { private final HashSet mMap; private final DatabaseHelper mDbHelper; private final String mLocale; + private final UserHistoryDictionary mUserHistoryDictionary; public UpdateDbTask(DatabaseHelper openHelper, HashSet pendingWrites, - String locale) { + String locale, UserHistoryDictionary dict) { mMap = pendingWrites; mLocale = locale; mDbHelper = openHelper; + mUserHistoryDictionary = dict; } /** Prune any old data if the database is getting too big. */ @@ -357,7 +361,8 @@ public class UserHistoryDictionary extends ExpandableDictionary { int totalRowCount = c.getCount(); // prune out old data if we have too much data if (totalRowCount > sMaxHistoryBigrams) { - int numDeleteRows = (totalRowCount - sMaxHistoryBigrams) + sDeleteHistoryBigrams; + int numDeleteRows = (totalRowCount - sMaxHistoryBigrams) + + sDeleteHistoryBigrams; int pairIdColumnId = c.getColumnIndex(FREQ_COLUMN_PAIR_ID); c.moveToFirst(); int count = 0; @@ -397,43 +402,70 @@ public class UserHistoryDictionary extends ExpandableDictionary { } db.execSQL("PRAGMA foreign_keys = ON;"); // Write all the entries to the db - Iterator iterator = mMap.iterator(); + final Iterator iterator = mMap.iterator(); while (iterator.hasNext()) { // TODO: this process of making a text search for each pair each time // is terribly inefficient. Optimize this. - Bigram bi = iterator.next(); + final Bigram bi = iterator.next(); // find pair id - final Cursor c; - if (null != bi.mWord1) { - c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, - MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND " - + MAIN_COLUMN_LOCALE + "=?", - new String[] { bi.mWord1, bi.mWord2, mLocale }, null, null, null); - } else { - c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, - MAIN_COLUMN_WORD1 + " IS NULL AND " + MAIN_COLUMN_WORD2 + "=? AND " - + MAIN_COLUMN_LOCALE + "=?", - new String[] { bi.mWord2, mLocale }, null, null, null); - } + Cursor c = null; + try { + if (null != bi.mWord1) { + c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, + MAIN_COLUMN_WORD1 + "=? AND " + MAIN_COLUMN_WORD2 + "=? AND " + + MAIN_COLUMN_LOCALE + "=?", + new String[] { bi.mWord1, bi.mWord2, mLocale }, null, null, + null); + } else { + c = db.query(MAIN_TABLE_NAME, new String[] { MAIN_COLUMN_ID }, + MAIN_COLUMN_WORD1 + " IS NULL AND " + MAIN_COLUMN_WORD2 + "=? AND " + + MAIN_COLUMN_LOCALE + "=?", + new String[] { bi.mWord2, mLocale }, null, null, null); + } - int pairId; - if (c.moveToFirst()) { - // existing pair - pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID)); - db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?", - new String[] { Integer.toString(pairId) }); - } else { - // new pair - Long pairIdLong = db.insert(MAIN_TABLE_NAME, null, - getContentValues(bi.mWord1, bi.mWord2, mLocale)); - pairId = pairIdLong.intValue(); + final int pairId; + if (c.moveToFirst()) { + // existing pair + pairId = c.getInt(c.getColumnIndex(MAIN_COLUMN_ID)); + db.delete(FREQ_TABLE_NAME, FREQ_COLUMN_PAIR_ID + "=?", + new String[] { Integer.toString(pairId) }); + } else { + // new pair + Long pairIdLong = db.insert(MAIN_TABLE_NAME, null, + getContentValues(bi.mWord1, bi.mWord2, mLocale)); + pairId = pairIdLong.intValue(); + } + // insert new frequency + final int freq; + if (bi.mWord1 == null) { + freq = FREQUENCY_FOR_TYPED; + } else { + final NextWord nw = mUserHistoryDictionary.getBigramWord( + bi.mWord1, bi.mWord2); + if (nw != null) { + final int tempFreq = nw.getFcValue(); + // TODO: Check whether the word is valid or not + if (UserHistoryForgettingCurveUtils.needsToSave( + (byte)tempFreq, false)) { + freq = tempFreq; + } else { + freq = -1; + } + } else { + freq = -1; + } + } + if (freq > 0) { + db.insert(FREQ_TABLE_NAME, null, getFrequencyContentValues(pairId, freq)); + } + } finally { + if (c != null) { + c.close(); + } } - c.close(); - - // insert new frequency - db.insert(FREQ_TABLE_NAME, null, getFrequencyContentValues(pairId, bi.mFrequency)); } + checkPruneData(db); sUpdatingDB = false; diff --git a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java index eb3881726..f30fee23e 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java @@ -16,14 +16,78 @@ package com.android.inputmethod.latin; +import android.text.format.DateUtils; +import android.util.Log; + public class UserHistoryForgettingCurveUtils { + private static final String TAG = UserHistoryForgettingCurveUtils.class.getSimpleName(); + private static final boolean DEBUG = false; private static final int FC_FREQ_MAX = 127; /* package */ static final int COUNT_MAX = 3; private static final int FC_LEVEL_MAX = 3; /* package */ static final int ELAPSED_TIME_MAX = 15; private static final int ELAPSED_TIME_INTERVAL_HOURS = 6; + private static final long ELAPSED_TIME_INTERVAL_MILLIS = ELAPSED_TIME_INTERVAL_HOURS + * DateUtils.HOUR_IN_MILLIS; private static final int HALF_LIFE_HOURS = 48; + private UserHistoryForgettingCurveUtils() { + // This utility class is not publicly instantiable. + } + + public static class ForgettingCurveParams { + private byte mFc; + long mLastTouchedTime = 0; + + private void updateLastTouchedTime() { + mLastTouchedTime = System.currentTimeMillis(); + } + + public ForgettingCurveParams() { + // TODO: Check whether this word is valid or not + this(System.currentTimeMillis()); + } + + private ForgettingCurveParams(long now) { + this((int)pushCount((byte)0, false), now, now); + } + + public ForgettingCurveParams(int fc, long now, long last) { + mFc = (byte)fc; + mLastTouchedTime = last; + updateElapsedTime(now); + } + + public byte getFc() { + updateElapsedTime(System.currentTimeMillis()); + return mFc; + } + + public int getFrequency() { + updateElapsedTime(System.currentTimeMillis()); + return UserHistoryForgettingCurveUtils.fcToFreq(mFc); + } + + public int notifyTypedAgainAndGetFrequency() { + updateLastTouchedTime(); + // TODO: Check whether this word is valid or not + mFc = pushCount(mFc, false); + return UserHistoryForgettingCurveUtils.fcToFreq(mFc); + } + + private void updateElapsedTime(long now) { + final int elapsedTimeCount = + (int)((now - mLastTouchedTime) / ELAPSED_TIME_INTERVAL_MILLIS); + if (elapsedTimeCount <= 0) { + return; + } + for (int i = 0; i < elapsedTimeCount; ++i) { + mLastTouchedTime += ELAPSED_TIME_INTERVAL_MILLIS; + mFc = pushElapsedTime(mFc); + } + } + } + /* package */ static int fcToElapsedTime(byte fc) { return fc & 0x0F; } @@ -38,8 +102,8 @@ public class UserHistoryForgettingCurveUtils { private static int calcFreq(int elapsedTime, int count, int level) { if (level <= 0) { - // Reserved words, just return 0 - return 0; + // Reserved words, just return -1 + return -1; } if (count == COUNT_MAX) { // Temporary promote because it's frequently typed recently @@ -87,12 +151,26 @@ public class UserHistoryForgettingCurveUtils { // Upgrade level ++level; count = 0; + if (DEBUG) { + Log.d(TAG, "Upgrade level."); + } } else { ++count; } return calcFc(0, count, level); } + // TODO: isValid should be false for a word whose frequency is 0, + // or that is not in the dictionary. + public static boolean needsToSave(byte fc, boolean isValid) { + int level = fcToLevel(fc); + if (isValid && level == 0) { + return false; + } + final int elapsedTime = fcToElapsedTime(fc); + return (elapsedTime < ELAPSED_TIME_MAX - 1 || level > 0); + } + private static class MathUtils { public static final int[][] SCORE_TABLE = new int[FC_LEVEL_MAX][ELAPSED_TIME_MAX + 1]; static { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 036ff74b8..91996674b 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -44,8 +44,10 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.Map; public class Utils { private Utils() { @@ -484,4 +486,40 @@ public class Utils { } return sDeviceOverrideValueMap.get(key); } + + private static final HashMap EMPTY_LT_HASH_MAP = new HashMap(); + private static final String LOCALE_AND_TIME_STR_SEPARATER = ","; + public static HashMap localeAndTimeStrToHashMap(String str) { + if (TextUtils.isEmpty(str)) { + return EMPTY_LT_HASH_MAP; + } + final String[] ss = str.split(LOCALE_AND_TIME_STR_SEPARATER); + final int N = ss.length; + if (N < 2 || N % 2 != 0) { + return EMPTY_LT_HASH_MAP; + } + final HashMap retval = new HashMap(); + for (int i = 0; i < N / 2; ++i) { + final String localeStr = ss[i]; + final long time = Long.valueOf(ss[i + 1]); + retval.put(localeStr, time); + } + return retval; + } + + public static String localeAndTimeHashMapToStr(HashMap map) { + if (map == null || map.isEmpty()) { + return ""; + } + final StringBuilder builder = new StringBuilder(); + for (String localeStr : map.keySet()) { + if (builder.length() > 0) { + builder.append(LOCALE_AND_TIME_STR_SEPARATER); + } + final Long time = map.get(localeStr); + builder.append(localeStr).append(LOCALE_AND_TIME_STR_SEPARATER); + builder.append(String.valueOf(time)); + } + return builder.toString(); + } } -- cgit v1.2.3-83-g751a From 48255b174736bd67480595317d87add5bc90ccdf Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Tue, 29 May 2012 13:16:38 +0900 Subject: Fix NumberFormatException Bug: 6567496 Change-Id: Ib0d9fab8496c8c856b94cce5812a263efbcb724f --- java/src/com/android/inputmethod/latin/Utils.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 91996674b..b3e46baf5 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -500,8 +500,8 @@ public class Utils { } final HashMap retval = new HashMap(); for (int i = 0; i < N / 2; ++i) { - final String localeStr = ss[i]; - final long time = Long.valueOf(ss[i + 1]); + final String localeStr = ss[i * 2]; + final long time = Long.valueOf(ss[i * 2 + 1]); retval.put(localeStr, time); } return retval; -- cgit v1.2.3-83-g751a From 027448e08a3df50a2ae9513d972fa60b047f6766 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Sat, 2 Jun 2012 22:50:38 +0900 Subject: Remove an unnecessary thread. bug: 6584677 While looking at bug 6584677, we found that LatinIME always spawns an unnecessary thread for Usability Study Mode. We don't assume this change will address the root cause of the bug, but we'd like to remove any suspicious noises in bugreports. Change-Id: Ie47d104f6cd77ec2ad164f13b4212cb4a70bcf1d --- java/src/com/android/inputmethod/latin/Utils.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index b3e46baf5..4178955bc 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -126,8 +126,9 @@ public class Utils { } public static RingCharBuffer init(InputMethodService context, boolean enabled, boolean usabilityStudy) { + if (!(enabled || usabilityStudy)) return null; sRingCharBuffer.mContext = context; - sRingCharBuffer.mEnabled = enabled || usabilityStudy; + sRingCharBuffer.mEnabled = true; UsabilityStudyLogUtils.getInstance().init(context); return sRingCharBuffer; } @@ -221,8 +222,6 @@ public class Utils { // TODO: remove code duplication with ResearchLog class private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName(); private static final String FILENAME = "log.txt"; - private static final UsabilityStudyLogUtils sInstance = - new UsabilityStudyLogUtils(); private final Handler mLoggingHandler; private File mFile; private File mDirectory; @@ -241,8 +240,13 @@ public class Utils { mLoggingHandler = new Handler(handlerThread.getLooper()); } + // Initialization-on-demand holder + private static class OnDemandInitializationHolder { + public static final UsabilityStudyLogUtils sInstance = new UsabilityStudyLogUtils(); + } + public static UsabilityStudyLogUtils getInstance() { - return sInstance; + return OnDemandInitializationHolder.sInstance; } public void init(InputMethodService ims) { -- cgit v1.2.3-83-g751a From 7214617622fce8f3fea6620e782c16336260a2a3 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 8 Jun 2012 16:00:02 +0900 Subject: Remove a slew of Eclipse warnings. Change-Id: I03236386aea13fbd4fb8eaeee18e0008aa136502 --- java/src/com/android/inputmethod/keyboard/KeyboardView.java | 1 + java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java | 2 -- java/src/com/android/inputmethod/latin/ExpandableDictionary.java | 4 +++- java/src/com/android/inputmethod/latin/LatinIME.java | 1 + java/src/com/android/inputmethod/latin/ResearchLogger.java | 4 ++-- java/src/com/android/inputmethod/latin/SettingsValues.java | 1 - java/src/com/android/inputmethod/latin/UserHistoryDictionary.java | 2 +- .../android/inputmethod/latin/UserHistoryForgettingCurveUtils.java | 4 ++-- java/src/com/android/inputmethod/latin/Utils.java | 2 -- .../com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java | 2 +- 10 files changed, 11 insertions(+), 12 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index 51a0f537f..18e01fb49 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -873,6 +873,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { keyPreview, ViewLayoutUtils.newLayoutParam(mPreviewPlacer, 0, 0)); } + @SuppressWarnings("deprecation") // setBackgroundDrawable is replaced by setBackground in API16 @Override public void showKeyPreview(PointerTracker tracker) { if (!mShowKeyPreviewPopup) return; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 5aa9a0887..4ab6832c3 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -21,8 +21,6 @@ import android.util.Log; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.latin.Constants; -import com.android.inputmethod.latin.ResearchLogger; -import com.android.inputmethod.latin.define.ProductionFlag; /** * Keyboard state machine. diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 34a92fd30..4a5471c85 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -514,8 +514,10 @@ public class ExpandableDictionary extends Dictionary { /** * Adds bigrams to the in-memory trie structure that is being used to retrieve any word + * @param word1 the first word of this bigram + * @param word2 the second word of this bigram * @param frequency frequency for this bigram - * @param addFrequency if true, it adds to current frequency, else it overwrites the old value + * @param fcp an instance of ForgettingCurveParams to use for decay policy * @return returns the final bigram frequency */ private int setBigramAndGetFrequency( diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index ae9e197a1..f5025e54a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -747,6 +747,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } + @Override public void onTargetApplicationKnown(final ApplicationInfo info) { mTargetApplicationInfo = info; } diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index bb003f766..a7e7738d8 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -101,13 +101,13 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static class NullOutputStream extends OutputStream { /** {@inheritDoc} */ @Override - public void write(byte[] buffer, int offset, int count) throws IOException { + public void write(byte[] buffer, int offset, int count) { // nop } /** {@inheritDoc} */ @Override - public void write(byte[] buffer) throws IOException { + public void write(byte[] buffer) { // nop } diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 4aae6a85e..dfe207cf2 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -29,7 +29,6 @@ import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; -import java.util.Map; /** * When you call the constructor of this class, you may want to change the current system locale by diff --git a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java index 9c54e0b81..10f92d29e 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryDictionary.java @@ -440,7 +440,7 @@ public class UserHistoryDictionary extends ExpandableDictionary { if (nw != null) { final ForgettingCurveParams fcp = nw.getFcParams(); final byte prevFc = word1Bigrams.get(word2); - final byte fc = (byte)fcp.getFc(); + final byte fc = fcp.getFc(); final boolean isValid = fcp.isValid(); if (prevFc > 0 && prevFc == fc) { // No need to update since we found no changes for this entry. diff --git a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java index e5516dc62..3ae1bd336 100644 --- a/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java +++ b/java/src/com/android/inputmethod/latin/UserHistoryForgettingCurveUtils.java @@ -50,7 +50,7 @@ public class UserHistoryForgettingCurveUtils { } private ForgettingCurveParams(long now, boolean isValid) { - this((int)pushCount((byte)0, isValid), now, now, isValid); + this(pushCount((byte)0, isValid), now, now, isValid); } /** This constructor is called when the user history bigram dictionary is being restored. */ @@ -201,7 +201,7 @@ public class UserHistoryForgettingCurveUtils { for (int i = 0; i < FC_LEVEL_MAX; ++i) { final double initialFreq; if (i >= 2) { - initialFreq = (double)FC_FREQ_MAX; + initialFreq = FC_FREQ_MAX; } else if (i == 1) { initialFreq = (double)FC_FREQ_MAX / 2; } else if (i == 0) { diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 4178955bc..903b5a357 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -44,10 +44,8 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; -import java.util.Collections; import java.util.Date; import java.util.HashMap; -import java.util.Map; public class Utils { private Utils() { diff --git a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java index 89c59f809..0c5d41a5c 100644 --- a/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java +++ b/java/src/com/android/inputmethod/latin/makedict/BinaryDictInputOutput.java @@ -788,7 +788,7 @@ public class BinaryDictInputOutput { // which is the best approximation. This is how we get the most precise result with // only four bits. final double stepSize = - (double)(MAX_TERMINAL_FREQUENCY - unigramFrequency) / (1.5 + MAX_BIGRAM_FREQUENCY); + (MAX_TERMINAL_FREQUENCY - unigramFrequency) / (1.5 + MAX_BIGRAM_FREQUENCY); final double firstStepStart = 1 + unigramFrequency + (stepSize / 2.0); final int discretizedFrequency = (int)((bigramFrequency - firstStepStart) / stepSize); // If the bigram freq is less than half-a-step higher than the unigram freq, we get -1 -- cgit v1.2.3-83-g751a From 9d71748ba48dbc8793f3e1ecddf5fd31b8e59613 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Fri, 8 Jun 2012 23:02:37 +0900 Subject: Fix an occurrence of nested batch edits. This is harmless, but against policy. Also, rework the checking code to be more readable, give more information, and be called for all relevant methods - and not for informative methods, which are not required to be in a batch edit. Change-Id: I03fa8b2e7d68a6a133f86be8a214671750c29256 --- .../com/android/inputmethod/latin/LatinIME.java | 11 +++----- .../inputmethod/latin/RichInputConnection.java | 31 +++++++++++++--------- java/src/com/android/inputmethod/latin/Utils.java | 10 +++++-- 3 files changed, 30 insertions(+), 22 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 5236591f6..00d4dfe93 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1804,14 +1804,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void pickSuggestionManually(final int index, final CharSequence suggestion, - int x, int y) { - mConnection.beginBatchEdit(getCurrentInputConnection()); - pickSuggestionManuallyWhileInBatchEdit(index, suggestion, x, y); - mConnection.endBatchEdit(); - } - - public void pickSuggestionManuallyWhileInBatchEdit(final int index, - final CharSequence suggestion, final int x, final int y) { + final int x, final int y) { final SuggestedWords suggestedWords = mSuggestionsView.getSuggestions(); // If this is a punctuation picked from the suggestion strip, pass it to onCodeInput if (suggestion.length() == 1 && isShowingPunctuationList()) { @@ -1846,7 +1839,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mKeyboardSwitcher.updateShiftState(); resetComposingState(true /* alsoResetLastComposedWord */); final CompletionInfo completionInfo = mApplicationSpecifiedCompletions[index]; + mConnection.beginBatchEdit(getCurrentInputConnection()); mConnection.commitCompletion(completionInfo); + mConnection.endBatchEdit(); if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.latinIME_pickApplicationSpecifiedCompletion(index, completionInfo.getText(), x, y); diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 227990acc..0c19bed05 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -65,66 +65,70 @@ public class RichInputConnection { if (--mNestLevel == 0 && null != mIC) mIC.endBatchEdit(); } + private void checkBatchEdit() { + if (mNestLevel != 1) { + // TODO: exception instead + Log.e(TAG, "Batch edit level incorrect : " + mNestLevel); + Log.e(TAG, Utils.getStackTrace(4)); + } + } + public void finishComposingText() { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.finishComposingText(); } public void commitText(final CharSequence text, final int i) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.commitText(text, i); } public int getCursorCapsMode(final int inputType) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead if (null == mIC) return Constants.TextUtils.CAP_MODE_OFF; return mIC.getCursorCapsMode(inputType); } public CharSequence getTextBeforeCursor(final int i, final int j) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead if (null != mIC) return mIC.getTextBeforeCursor(i, j); return null; } public CharSequence getTextAfterCursor(final int i, final int j) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead if (null != mIC) return mIC.getTextAfterCursor(i, j); return null; } public void deleteSurroundingText(final int i, final int j) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.deleteSurroundingText(i, j); } public void performEditorAction(final int actionId) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead if (null != mIC) mIC.performEditorAction(actionId); } public void sendKeyEvent(final KeyEvent keyEvent) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.sendKeyEvent(keyEvent); } public void setComposingText(final CharSequence text, final int i) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.setComposingText(text, i); } public void setSelection(final int from, final int to) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.setSelection(from, to); } public void commitCorrection(final CorrectionInfo correctionInfo) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.commitCorrection(correctionInfo); } public void commitCompletion(final CompletionInfo completionInfo) { - if (mNestLevel <= 0) Log.e(TAG, "Batch edit not in progress!"); // TODO: exception instead + checkBatchEdit(); if (null != mIC) mIC.commitCompletion(completionInfo); } @@ -316,6 +320,7 @@ public class RichInputConnection { } public void removeTrailingSpace() { + checkBatchEdit(); final CharSequence lastOne = getTextBeforeCursor(1, 0); if (lastOne != null && lastOne.length() == 1 && lastOne.charAt(0) == Keyboard.CODE_SPACE) { @@ -372,6 +377,7 @@ public class RichInputConnection { } public boolean revertDoubleSpace() { + checkBatchEdit(); // Here we test whether we indeed have a period and a space before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0); @@ -395,6 +401,7 @@ public class RichInputConnection { } public boolean revertSwapPunctuation() { + checkBatchEdit(); // Here we test whether we indeed have a space and something else before us. This should not // be needed, but it's there just in case something went wrong. final CharSequence textBeforeCursor = getTextBeforeCursor(2, 0); diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 903b5a357..f2d21ab9b 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -204,18 +204,24 @@ public class Utils { } // Get the current stack trace - public static String getStackTrace() { + public static String getStackTrace(final int limit) { StringBuilder sb = new StringBuilder(); try { throw new RuntimeException(); } catch (RuntimeException e) { StackTraceElement[] frames = e.getStackTrace(); // Start at 1 because the first frame is here and we don't care about it - for (int j = 1; j < frames.length; ++j) sb.append(frames[j].toString() + "\n"); + for (int j = 1; j < frames.length && j < limit + 1; ++j) { + sb.append(frames[j].toString() + "\n"); + } } return sb.toString(); } + public static String getStackTrace() { + return getStackTrace(Integer.MAX_VALUE); + } + public static class UsabilityStudyLogUtils { // TODO: remove code duplication with ResearchLog class private static final String USABILITY_TAG = UsabilityStudyLogUtils.class.getSimpleName(); -- cgit v1.2.3-83-g751a From 7c406ed655be0b6a12c1792d810504a32ec878fd Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Wed, 13 Jun 2012 02:11:45 +0900 Subject: Tentatively remove a dependency on WordCallback (A3) Bug: 6252660 Bug: 6166228 Bug: 2704000 Bug: 6225530 Change-Id: Id5a59eaec2aeefa0ba4524420a8e035d383f6545 --- .../inputmethod/latin/ExpandableDictionary.java | 53 ++++++++++++---------- .../android/inputmethod/latin/SuggestedWords.java | 3 +- java/src/com/android/inputmethod/latin/Utils.java | 11 +++++ 3 files changed, 43 insertions(+), 24 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 4a5471c85..f5886aa12 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -21,6 +21,7 @@ import android.content.Context; import com.android.inputmethod.keyboard.KeyDetector; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.ProximityInfo; +import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.UserHistoryForgettingCurveUtils.ForgettingCurveParams; import java.util.ArrayList; @@ -258,12 +259,14 @@ public class ExpandableDictionary extends Dictionary { if (codes.size() >= BinaryDictionary.MAX_WORD_LENGTH) { return; } - getWordsInner(codes, prevWordForBigrams, callback, proximityInfo); + final ArrayList suggestions = + getWordsInner(codes, prevWordForBigrams, proximityInfo); + Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback); } - protected final void getWordsInner(final WordComposer codes, - final CharSequence prevWordForBigrams, final WordCallback callback, - final ProximityInfo proximityInfo) { + protected final ArrayList getWordsInner(final WordComposer codes, + final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo) { + final ArrayList suggestions = new ArrayList(); mInputLength = codes.size(); if (mCodes.length < mInputLength) mCodes = new int[mInputLength][]; final int[] xCoordinates = codes.getXCoordinates(); @@ -281,10 +284,11 @@ public class ExpandableDictionary extends Dictionary { proximityInfo.fillArrayWithNearestKeyCodes(x, y, codes.getCodeAt(i), mCodes[i]); } mMaxDepth = mInputLength * 3; - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, callback); + getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, -1, suggestions); for (int i = 0; i < mInputLength; i++) { - getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, callback); + getWordsRec(mRoots, codes, mWordBuilder, 0, false, 1, 0, i, suggestions); } + return suggestions; } @Override @@ -368,24 +372,27 @@ public class ExpandableDictionary extends Dictionary { * @param word the word to insert, as an array of code points * @param depth the depth of the node in the tree * @param finalFreq the frequency for this word + * @param suggestions the suggestion collection to add the suggestions to * @return whether there is still space for more words. - * @see Dictionary.WordCallback#addWord(char[], int, int, int, int, int) */ private boolean addWordAndShortcutsFromNode(final Node node, final char[] word, final int depth, - final int finalFreq, final WordCallback callback) { + final int finalFreq, final ArrayList suggestions) { if (finalFreq > 0 && !node.mShortcutOnly) { - if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, Dictionary.UNIGRAM)) { - return false; - } + // Use KIND_CORRECTION always. This dictionary does not really have a notion of + // COMPLETION against CORRECTION; we could artificially add one by looking at + // the respective size of the typed word and the suggestion if it matters sometime + // in the future. + suggestions.add(new SuggestedWordInfo(new String(word, 0, depth + 1), finalFreq, + SuggestedWordInfo.KIND_CORRECTION)); + if (suggestions.size() >= Suggest.MAX_SUGGESTIONS) return false; } if (null != node.mShortcutTargets) { final int length = node.mShortcutTargets.size(); for (int shortcutIndex = 0; shortcutIndex < length; ++shortcutIndex) { final char[] shortcut = node.mShortcutTargets.get(shortcutIndex); - if (!callback.addWord(shortcut, 0, shortcut.length, finalFreq, mDicTypeId, - Dictionary.UNIGRAM)) { - return false; - } + suggestions.add(new SuggestedWordInfo(new String(shortcut, 0, shortcut.length), + finalFreq, SuggestedWordInfo.KIND_SHORTCUT)); + if (suggestions.size() > Suggest.MAX_SUGGESTIONS) return false; } } return true; @@ -408,12 +415,12 @@ public class ExpandableDictionary extends Dictionary { * case we skip over some punctuations such as apostrophe in the traversal. That is, if you type * "wouldve", it could be matching "would've", so the depth will be one more than the * inputIndex - * @param callback the callback class for adding a word + * @param suggestions the list in which to add suggestions */ // TODO: Share this routine with the native code for BinaryDictionary protected void getWordsRec(NodeArray roots, final WordComposer codes, final char[] word, final int depth, final boolean completion, int snr, int inputIndex, int skipPos, - WordCallback callback) { + final ArrayList suggestions) { final int count = roots.mLength; final int codeSize = mInputLength; // Optimization: Prune out words that are too long compared to how much was typed. @@ -443,14 +450,14 @@ public class ExpandableDictionary extends Dictionary { } else { finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength); } - if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, callback)) { + if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, suggestions)) { // No space left in the queue, bail out return; } } if (children != null) { getWordsRec(children, codes, word, depth + 1, true, snr, inputIndex, - skipPos, callback); + skipPos, suggestions); } } else if ((c == Keyboard.CODE_SINGLE_QUOTE && currentChars[0] != Keyboard.CODE_SINGLE_QUOTE) || depth == skipPos) { @@ -458,7 +465,7 @@ public class ExpandableDictionary extends Dictionary { word[depth] = c; if (children != null) { getWordsRec(children, codes, word, depth + 1, completion, snr, inputIndex, - skipPos, callback); + skipPos, suggestions); } } else { // Don't use alternatives if we're looking for missing characters @@ -483,7 +490,7 @@ public class ExpandableDictionary extends Dictionary { snr * addedAttenuation, mInputLength); } if (!addWordAndShortcutsFromNode(node, word, depth, finalFreq, - callback)) { + suggestions)) { // No space left in the queue, bail out return; } @@ -491,12 +498,12 @@ public class ExpandableDictionary extends Dictionary { if (children != null) { getWordsRec(children, codes, word, depth + 1, true, snr * addedAttenuation, inputIndex + 1, - skipPos, callback); + skipPos, suggestions); } } else if (children != null) { getWordsRec(children, codes, word, depth + 1, false, snr * addedAttenuation, inputIndex + 1, - skipPos, callback); + skipPos, suggestions); } } } diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 1ed91fe71..45ac9ff53 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -129,10 +129,11 @@ public class SuggestedWords { public static final int KIND_BLACKLIST = 4; // Blacklisted word public static final int KIND_HARDCODED = 5; // Hardcoded suggestion, e.g. punctuation public static final int KIND_APP_DEFINED = 6; // Suggested by the application + public static final int KIND_SHORTCUT = 7; // A shortcut private final String mWordStr; public final CharSequence mWord; public final int mScore; - public final int mKind; + public final int mKind; // one of the KIND_* constants above public final int mCodePointCount; private String mDebugString = ""; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index f2d21ab9b..a44b1f9ad 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -44,6 +44,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.nio.channels.FileChannel; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Date; import java.util.HashMap; @@ -530,4 +531,14 @@ public class Utils { } return builder.toString(); } + + public static void addAllSuggestions(final int dicTypeId, final int dataType, + final ArrayList suggestions, + final Dictionary.WordCallback callback) { + for (SuggestedWordInfo suggestion : suggestions) { + final String suggestionStr = suggestion.mWord.toString(); + callback.addWord(suggestionStr.toCharArray(), 0, suggestionStr.length(), + suggestion.mScore, dicTypeId, dataType); + } + } } -- cgit v1.2.3-83-g751a From 73680097996ea2ddbca3f84144a00ce3ba66b763 Mon Sep 17 00:00:00 2001 From: Satoshi Kataoka Date: Mon, 25 Jun 2012 17:44:54 +0900 Subject: Change JNI for Gesture Change-Id: I774a0052038d16677f60f7efa11fd266cb5f3088 --- .../inputmethod/latin/BinaryDictionary.java | 45 +++++++++++++--------- .../com/android/inputmethod/latin/Dictionary.java | 5 ++- .../inputmethod/latin/DictionaryFactory.java | 6 +-- .../latin/ExpandableBinaryDictionary.java | 2 +- .../inputmethod/latin/ExpandableDictionary.java | 5 ++- .../src/com/android/inputmethod/latin/Suggest.java | 4 +- java/src/com/android/inputmethod/latin/Utils.java | 2 +- .../spellcheck/AndroidSpellCheckerService.java | 4 +- ..._android_inputmethod_latin_BinaryDictionary.cpp | 25 ++++++++---- native/jni/src/dictionary.h | 14 ++++--- 10 files changed, 68 insertions(+), 44 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index d0613bd72..b7a510021 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -40,6 +40,7 @@ public class BinaryDictionary extends Dictionary { */ public static final int MAX_WORD_LENGTH = 48; public static final int MAX_WORDS = 18; + public static final int MAX_SPACES = 16; private static final String TAG = "BinaryDictionary"; private static final int MAX_BIGRAMS = 60; @@ -51,6 +52,7 @@ public class BinaryDictionary extends Dictionary { private final int[] mInputCodes = new int[MAX_WORD_LENGTH]; private final char[] mOutputChars = new char[MAX_WORD_LENGTH * MAX_WORDS]; private final char[] mOutputChars_bigrams = new char[MAX_WORD_LENGTH * MAX_BIGRAMS]; + private final int[] mSpaceIndices = new int[MAX_SPACES]; private final int[] mScores = new int[MAX_WORDS]; private final int[] mBigramScores = new int[MAX_BIGRAMS]; @@ -65,14 +67,12 @@ public class BinaryDictionary extends Dictionary { * @param offset the offset of the dictionary data within the file. * @param length the length of the binary data. * @param useFullEditDistance whether to use the full edit distance in suggestions + * @param dicTypeId the dictionary type id of the dictionary */ public BinaryDictionary(final Context context, final String filename, final long offset, final long length, - final boolean useFullEditDistance, final Locale locale) { - // Note: at the moment a binary dictionary is always of the "main" type. - // Initializing this here will help transitioning out of the scheme where - // the Suggest class knows everything about every single dictionary. - mDicTypeId = Suggest.DIC_MAIN; + final boolean useFullEditDistance, final Locale locale, final int dicTypeId) { + mDicTypeId = dicTypeId; mUseFullEditDistance = useFullEditDistance; loadDictionary(filename, offset, length); } @@ -87,8 +87,10 @@ public class BinaryDictionary extends Dictionary { private native int getFrequencyNative(long dict, int[] word, int wordLength); private native boolean isValidBigramNative(long dict, int[] word1, int[] word2); private native int getSuggestionsNative(long dict, long proximityInfo, int[] xCoordinates, - int[] yCoordinates, int[] inputCodes, int codesSize, int[] prevWordForBigrams, - boolean useFullEditDistance, char[] outputChars, int[] scores); + int[] yCoordinates, int[] times, int[] pointerIds, int[] inputCodes, int codesSize, + int commitPoint, boolean isGesture, int dicTypeId, + int[] prevWordCodePointArray, boolean useFullEditDistance, char[] outputChars, + int[] scores, int[] outputIndices); private native int getBigramsNative(long dict, int[] prevWord, int prevWordLength, int[] inputCodes, int inputCodesLength, char[] outputChars, int[] scores, int maxWordLength, int maxBigrams); @@ -131,7 +133,7 @@ public class BinaryDictionary extends Dictionary { ++len; } if (len > 0) { - callback.addWord(mOutputChars_bigrams, start, len, mBigramScores[j], + callback.addWord(mOutputChars_bigrams, null, start, len, mBigramScores[j], mDicTypeId, Dictionary.BIGRAM); } } @@ -141,9 +143,9 @@ public class BinaryDictionary extends Dictionary { @Override public void getWords(final WordComposer codes, final CharSequence prevWordForBigrams, final WordCallback callback, final ProximityInfo proximityInfo) { - final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, - mScores); + final int count = getSuggestions(codes, prevWordForBigrams, proximityInfo, mOutputChars, + mScores, mSpaceIndices); for (int j = 0; j < count; ++j) { if (mScores[j] < 1) break; final int start = j * MAX_WORD_LENGTH; @@ -152,7 +154,7 @@ public class BinaryDictionary extends Dictionary { ++len; } if (len > 0) { - callback.addWord(mOutputChars, start, len, mScores[j], mDicTypeId, + callback.addWord(mOutputChars, null, start, len, mScores[j], mDicTypeId, Dictionary.UNIGRAM); } } @@ -165,7 +167,7 @@ public class BinaryDictionary extends Dictionary { // proximityInfo may not be null. /* package for test */ int getSuggestions(final WordComposer codes, final CharSequence prevWordForBigrams, final ProximityInfo proximityInfo, - char[] outputChars, int[] scores) { + char[] outputChars, int[] scores, int[] spaceIndices) { if (!isValidDictionary()) return -1; final int codesSize = codes.size(); @@ -179,14 +181,21 @@ public class BinaryDictionary extends Dictionary { Arrays.fill(outputChars, (char) 0); Arrays.fill(scores, 0); - final int[] prevWordCodePointArray = null == prevWordForBigrams + // TODO: toLowerCase in the native code + final int[] prevWordCodePointArray = (null == prevWordForBigrams) ? null : StringUtils.toCodePointArray(prevWordForBigrams.toString()); - // TODO: pass the previous word to native code - return getSuggestionsNative( - mNativeDict, proximityInfo.getNativeProximityInfo(), - codes.getXCoordinates(), codes.getYCoordinates(), mInputCodes, codesSize, - prevWordCodePointArray, mUseFullEditDistance, outputChars, scores); + int[] emptyArray = new int[codesSize]; + Arrays.fill(emptyArray, 0); + + //final int commitPoint = codes.getCommitPoint(); + //codes.clearCommitPoint(); + + return getSuggestionsNative(mNativeDict, proximityInfo.getNativeProximityInfo(), + codes.getXCoordinates(), codes.getYCoordinates(), emptyArray, emptyArray, mInputCodes, + codesSize, 0 /* unused */, false, mDicTypeId, + prevWordCodePointArray, mUseFullEditDistance, + outputChars, scores, spaceIndices); } public static float calcNormalizedScore(String before, String after, int score) { diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 9c3d46e70..c75e55d80 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -41,6 +41,7 @@ public abstract class Dictionary { * Adds a word to a list of suggestions. The word is expected to be ordered based on * the provided score. * @param word the character array containing the word + * @param spaceIndices the indices of inserted spaces * @param wordOffset starting offset of the word in the character array * @param wordLength length of valid characters in the character array * @param score the score of occurrence. This is normalized between 1 and 255, but @@ -49,8 +50,8 @@ public abstract class Dictionary { * @param dataType tells type of this data, either UNIGRAM or BIGRAM * @return true if the word was added, false if no more words are required */ - boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId, - int dataType); + boolean addWord(char[] word, int[] spaceIndices, int wordOffset, int wordLength, int score, + int dicTypeId, int dataType); } /** diff --git a/java/src/com/android/inputmethod/latin/DictionaryFactory.java b/java/src/com/android/inputmethod/latin/DictionaryFactory.java index a22d73af7..6d77c4dd2 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFactory.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFactory.java @@ -59,7 +59,7 @@ public class DictionaryFactory { for (final AssetFileAddress f : assetFileList) { final BinaryDictionary binaryDictionary = new BinaryDictionary(context, f.mFilename, f.mOffset, f.mLength, - useFullEditDistance, locale); + useFullEditDistance, locale, Suggest.DIC_MAIN); if (binaryDictionary.isValidDictionary()) { dictList.add(binaryDictionary); } @@ -112,7 +112,7 @@ public class DictionaryFactory { return null; } return new BinaryDictionary(context, sourceDir, afd.getStartOffset(), afd.getLength(), - false /* useFullEditDistance */, locale); + false /* useFullEditDistance */, locale, Suggest.DIC_MAIN); } catch (android.content.res.Resources.NotFoundException e) { Log.e(TAG, "Could not find the resource"); return null; @@ -140,7 +140,7 @@ public class DictionaryFactory { long startOffset, long length, final boolean useFullEditDistance, Locale locale) { if (dictionary.isFile()) { return new BinaryDictionary(context, dictionary.getAbsolutePath(), startOffset, length, - useFullEditDistance, locale); + useFullEditDistance, locale, Suggest.DIC_MAIN); } else { Log.e(TAG, "Could not find the file. path=" + dictionary.getAbsolutePath()); return null; diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index c65404cbc..41d4aa061 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -306,7 +306,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { // Build the new binary dictionary final BinaryDictionary newBinaryDictionary = new BinaryDictionary(mContext, filename, 0, length, true /* useFullEditDistance */, - null); + null, mDicTypeId); if (mBinaryDictionary != null) { // Ensure all threads accessing the current dictionary have finished before swapping in diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index f5886aa12..c989614fb 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -660,8 +660,9 @@ public class ExpandableDictionary extends Dictionary { } while (node != null); if (freq >= 0) { - callback.addWord(mLookedUpString, index, BinaryDictionary.MAX_WORD_LENGTH - index, - freq, mDicTypeId, Dictionary.BIGRAM); + callback.addWord(mLookedUpString, null, index, + BinaryDictionary.MAX_WORD_LENGTH - index, freq, mDicTypeId, + Dictionary.BIGRAM); } } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 892245402..0938bd127 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -439,8 +439,8 @@ public class Suggest implements Dictionary.WordCallback { // TODO: Use codepoint instead of char @Override - public boolean addWord(final char[] word, final int offset, final int length, int score, - final int dicTypeId, final int dataType) { + public boolean addWord(final char[] word, int[] indices, final int offset, final int length, + int score, final int dicTypeId, final int dataType) { int dataTypeForLog = dataType; final ArrayList suggestions; final int prefMaxSuggestions; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index a44b1f9ad..19ac71876 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -537,7 +537,7 @@ public class Utils { final Dictionary.WordCallback callback) { for (SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); - callback.addWord(suggestionStr.toCharArray(), 0, suggestionStr.length(), + callback.addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(), suggestion.mScore, dicTypeId, dataType); } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 7fffc31c0..0bbf2acb1 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -238,8 +238,8 @@ public class AndroidSpellCheckerService extends SpellCheckerService } @Override - synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, - int dicTypeId, int dataType) { + synchronized public boolean addWord(char[] word, int[] spaceIndices, int wordOffset, + int wordLength, int score, int dicTypeId, int dataType) { final int positionIndex = Arrays.binarySearch(mScores, 0, mLength, score); // binarySearch returns the index if the element exists, and - - 1 // if it doesn't. See documentation for binarySearch. diff --git a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp index d10dc962e..3fa45da55 100644 --- a/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp +++ b/native/jni/com_android_inputmethod_latin_BinaryDictionary.cpp @@ -128,28 +128,37 @@ static jlong latinime_BinaryDictionary_open(JNIEnv *env, jobject object, static int latinime_BinaryDictionary_getSuggestions(JNIEnv *env, jobject object, jlong dict, jlong proximityInfo, jintArray xCoordinatesArray, jintArray yCoordinatesArray, - jintArray inputArray, jint arraySize, jintArray prevWordForBigrams, - jboolean useFullEditDistance, jcharArray outputArray, jintArray frequencyArray) { - Dictionary *dictionary = (Dictionary*)dict; + jintArray timesArray, jintArray pointerIdArray, jintArray inputArray, jint arraySize, + jint commitPoint, jboolean isGesture, jint dicTypeId, + jintArray prevWordForBigrams, jboolean useFullEditDistance, jcharArray outputArray, + jintArray frequencyArray, jintArray spaceIndexArray) { + Dictionary *dictionary = (Dictionary*) dict; if (!dictionary) return 0; ProximityInfo *pInfo = (ProximityInfo*)proximityInfo; int *xCoordinates = env->GetIntArrayElements(xCoordinatesArray, 0); int *yCoordinates = env->GetIntArrayElements(yCoordinatesArray, 0); + int *times = env->GetIntArrayElements(timesArray, 0); + int *pointerIds = env->GetIntArrayElements(pointerIdArray, 0); int *frequencies = env->GetIntArrayElements(frequencyArray, 0); int *inputCodes = env->GetIntArrayElements(inputArray, 0); jchar *outputChars = env->GetCharArrayElements(outputArray, 0); + int *spaceIndices = env->GetIntArrayElements(spaceIndexArray, 0); jint *prevWordChars = prevWordForBigrams ? env->GetIntArrayElements(prevWordForBigrams, 0) : 0; jsize prevWordLength = prevWordChars ? env->GetArrayLength(prevWordForBigrams) : 0; - int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, inputCodes, - arraySize, prevWordChars, prevWordLength, useFullEditDistance, - (unsigned short*) outputChars, frequencies); + int count = dictionary->getSuggestions(pInfo, xCoordinates, yCoordinates, times, pointerIds, + inputCodes, arraySize, prevWordChars, prevWordLength, commitPoint, isGesture, + dicTypeId, useFullEditDistance, (unsigned short*) outputChars, + frequencies, spaceIndices); if (prevWordChars) { env->ReleaseIntArrayElements(prevWordForBigrams, prevWordChars, JNI_ABORT); } + env->ReleaseIntArrayElements(spaceIndexArray, spaceIndices, 0); env->ReleaseCharArrayElements(outputArray, outputChars, 0); env->ReleaseIntArrayElements(inputArray, inputCodes, JNI_ABORT); env->ReleaseIntArrayElements(frequencyArray, frequencies, 0); + env->ReleaseIntArrayElements(pointerIdArray, pointerIds, 0); + env->ReleaseIntArrayElements(timesArray, times, 0); env->ReleaseIntArrayElements(yCoordinatesArray, yCoordinates, 0); env->ReleaseIntArrayElements(xCoordinatesArray, xCoordinates, 0); return count; @@ -251,8 +260,8 @@ void releaseDictBuf(void* dictBuf, const size_t length, int fd) { static JNINativeMethod sMethods[] = { {"openNative", "(Ljava/lang/String;JJIIII)J", (void*)latinime_BinaryDictionary_open}, {"closeNative", "(J)V", (void*)latinime_BinaryDictionary_close}, - {"getSuggestionsNative", "(JJ[I[I[II[IZ[C[I)I", - (void*)latinime_BinaryDictionary_getSuggestions}, + {"getSuggestionsNative", "(JJ[I[I[I[I[IIIZI[IZ[C[I[I)I", + (void*) latinime_BinaryDictionary_getSuggestions}, {"getFrequencyNative", "(J[II)I", (void*)latinime_BinaryDictionary_getFrequency}, {"isValidBigramNative", "(J[I[I)Z", (void*)latinime_BinaryDictionary_isValidBigram}, {"getBigramsNative", "(J[II[II[C[III)I", (void*)latinime_BinaryDictionary_getBigrams}, diff --git a/native/jni/src/dictionary.h b/native/jni/src/dictionary.h index fd69f79e3..76b25e59a 100644 --- a/native/jni/src/dictionary.h +++ b/native/jni/src/dictionary.h @@ -34,15 +34,19 @@ class Dictionary { int fullWordMultiplier, int maxWordLength, int maxWords); int getSuggestions(ProximityInfo *proximityInfo, int *xcoordinates, int *ycoordinates, - int *codes, int codesSize, const int32_t* prevWordChars, const int prevWordLength, - bool useFullEditDistance, unsigned short *outWords, int *frequencies) const { + int *times, int *pointerIds, int *codes, int codesSize, int *prevWordChars, + int prevWordLength, int commitPoint, bool isGesture, int dicTypeId, + bool useFullEditDistance, unsigned short *outWords, + int *frequencies, int *spaceIndices) { + int result = 0; std::map bigramMap; uint8_t bigramFilter[BIGRAM_FILTER_BYTE_SIZE]; mBigramDictionary->fillBigramAddressToFrequencyMapAndFilter(prevWordChars, prevWordLength, &bigramMap, bigramFilter); - return mUnigramDictionary->getSuggestions(proximityInfo, - xcoordinates, ycoordinates, codes, codesSize, &bigramMap, - bigramFilter, useFullEditDistance, outWords, frequencies); + result = mUnigramDictionary->getSuggestions(proximityInfo, xcoordinates, + ycoordinates, codes, codesSize, &bigramMap, bigramFilter, + useFullEditDistance, outWords, frequencies); + return result; } int getBigrams(const int32_t *word, int length, int *codes, int codesSize, -- cgit v1.2.3-83-g751a From 2225b3bace388ba0b8789254da09fb9f6a6250e3 Mon Sep 17 00:00:00 2001 From: Jean Chalard Date: Thu, 21 Jun 2012 13:24:13 +0900 Subject: Do away with Utils#addAllSuggestions (A14) It's not used any more. Change-Id: Id9da40fdbf7078f3ac647d1368237d6601f5a2ba --- java/src/com/android/inputmethod/latin/BinaryDictionary.java | 2 -- .../com/android/inputmethod/latin/ExpandableDictionary.java | 2 -- java/src/com/android/inputmethod/latin/Utils.java | 10 ---------- .../latin/spellcheck/AndroidSpellCheckerService.java | 2 +- 4 files changed, 1 insertion(+), 15 deletions(-) (limited to 'java/src/com/android/inputmethod/latin/Utils.java') diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 6b6ec2b45..9b950d260 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -141,7 +141,6 @@ public class BinaryDictionary extends Dictionary { mBigramScores[j], SuggestedWordInfo.KIND_CORRECTION)); } } - Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback); return suggestions; } @@ -168,7 +167,6 @@ public class BinaryDictionary extends Dictionary { mScores[j], SuggestedWordInfo.KIND_CORRECTION)); } } - Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback); return suggestions; } diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 7d131a664..e48e9e974 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -262,7 +262,6 @@ public class ExpandableDictionary extends Dictionary { } final ArrayList suggestions = getWordsInner(codes, prevWordForBigrams, proximityInfo); - Utils.addAllSuggestions(mDicTypeId, Dictionary.UNIGRAM, suggestions, callback); return suggestions; } @@ -618,7 +617,6 @@ public class ExpandableDictionary extends Dictionary { if (!reloadDictionaryIfRequired()) { final ArrayList suggestions = new ArrayList(); runBigramReverseLookUp(previousWord, suggestions); - Utils.addAllSuggestions(mDicTypeId, Dictionary.BIGRAM, suggestions, callback); return suggestions; } return null; diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java index 19ac71876..8f71de0e7 100644 --- a/java/src/com/android/inputmethod/latin/Utils.java +++ b/java/src/com/android/inputmethod/latin/Utils.java @@ -531,14 +531,4 @@ public class Utils { } return builder.toString(); } - - public static void addAllSuggestions(final int dicTypeId, final int dataType, - final ArrayList suggestions, - final Dictionary.WordCallback callback) { - for (SuggestedWordInfo suggestion : suggestions) { - final String suggestionStr = suggestion.mWord.toString(); - callback.addWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(), - suggestion.mScore, dicTypeId, dataType); - } - } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index f68fc10ea..acaf3d235 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -792,7 +792,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService composer, prevWord, suggestionsGatherer, dictInfo.mProximityInfo); for (final SuggestedWordInfo suggestion : suggestions) { final String suggestionStr = suggestion.mWord.toString(); - suggestionsGatherer.oldAddWord(suggestionStr.toCharArray(), 0, + suggestionsGatherer.oldAddWord(suggestionStr.toCharArray(), null, 0, suggestionStr.length(), suggestion.mScore, 0 /* ignored */, Dictionary.UNIGRAM); } -- cgit v1.2.3-83-g751a