diff options
58 files changed, 475 insertions, 2584 deletions
diff --git a/common/src/com/android/inputmethod/latin/common/Constants.java b/common/src/com/android/inputmethod/latin/common/Constants.java index a860d3560..baa859268 100644 --- a/common/src/com/android/inputmethod/latin/common/Constants.java +++ b/common/src/com/android/inputmethod/latin/common/Constants.java @@ -163,7 +163,6 @@ public final class Constants { // TODO: replace the following constants with state in InputTransaction? public static final int NOT_A_COORDINATE = -1; public static final int SUGGESTION_STRIP_COORDINATE = -2; - public static final int SPELL_CHECKER_COORDINATE = -3; public static final int EXTERNAL_KEYBOARD_COORDINATE = -4; // A hint on how many characters to cache from the TextView. A good value of this is given by @@ -174,13 +173,6 @@ public final class Constants { // right for this. public static final int MAX_CHARACTERS_FOR_RECAPITALIZATION = 1024 * 100; - // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h - public static final int DICTIONARY_MAX_WORD_LENGTH = 48; - - // (MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1)-gram is supported in Java side. Needs to modify - // MAX_PREV_WORD_COUNT_FOR_N_GRAM in native/jni/src/defines.h for suggestions. - public static final int MAX_PREV_WORD_COUNT_FOR_N_GRAM = 3; - // Key events coming any faster than this are long-presses. public static final int LONG_PRESS_MILLISECONDS = 200; // TODO: Set this value appropriately. @@ -214,8 +206,6 @@ public final class Constants { public static final int CODE_DASH = '-'; public static final int CODE_SINGLE_QUOTE = '\''; public static final int CODE_DOUBLE_QUOTE = '"'; - public static final int CODE_QUESTION_MARK = '?'; - public static final int CODE_EXCLAMATION_MARK = '!'; public static final int CODE_SLASH = '/'; public static final int CODE_BACKSLASH = '\\'; public static final int CODE_VERTICAL_BAR = '|'; @@ -330,6 +320,10 @@ public final class Constants { */ public static final int DEFAULT_GESTURE_POINTS_CAPACITY = 128; + public static final int MAX_IME_DECODER_RESULTS = 20; + public static final int DECODER_SCORE_SCALAR = 1000000; + public static final int DECODER_MAX_SCORE = 1000000000; + private Constants() { // This utility class is not publicly instantiable. } diff --git a/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java b/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java new file mode 100644 index 000000000..10974634d --- /dev/null +++ b/common/src/com/android/inputmethod/latin/common/UnicodeSurrogate.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2015 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.common; + +/** + * Emojis are supplementary characters expressed as a low+high pair. For instance, + * the emoji U+1F625 is encoded as "\uD83D\uDE25" in UTF-16, where '\uD83D' is in + * the range of [0xd800, 0xdbff] and '\uDE25' is in the range of [0xdc00, 0xdfff]. + * {@see http://docs.oracle.com/javase/6/docs/api/java/lang/Character.html#unicode} + */ +public final class UnicodeSurrogate { + private static final char LOW_SURROGATE_MIN = '\uD800'; + private static final char LOW_SURROGATE_MAX = '\uDBFF'; + private static final char HIGH_SURROGATE_MIN = '\uDC00'; + private static final char HIGH_SURROGATE_MAX = '\uDFFF'; + + public static boolean isLowSurrogate(final char c) { + return c >= LOW_SURROGATE_MIN && c <= LOW_SURROGATE_MAX; + } + + public static boolean isHighSurrogate(final char c) { + return c >= HIGH_SURROGATE_MIN && c <= HIGH_SURROGATE_MAX; + } +} diff --git a/java-overridable/src/com/android/inputmethod/latin/define/DecoderSpecificConstants.java b/java-overridable/src/com/android/inputmethod/latin/define/DecoderSpecificConstants.java new file mode 100644 index 000000000..eb4a3eb59 --- /dev/null +++ b/java-overridable/src/com/android/inputmethod/latin/define/DecoderSpecificConstants.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2015 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; + +/** + * Decoder specific constants for LatinIme. + */ +public class DecoderSpecificConstants { + + // Must be equal to MAX_WORD_LENGTH in native/jni/src/defines.h + public static final int DICTIONARY_MAX_WORD_LENGTH = 48; + + // (MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1)-gram is supported in Java side. Needs to modify + // MAX_PREV_WORD_COUNT_FOR_N_GRAM in native/jni/src/defines.h for suggestions. + public static final int MAX_PREV_WORD_COUNT_FOR_N_GRAM = 3; +} diff --git a/java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java b/java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java deleted file mode 100644 index fe1d846d8..000000000 --- a/java-overridable/src/com/android/inputmethod/latin/personalization/ContextualDictionaryUpdater.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import android.content.Context; - -import com.android.inputmethod.latin.DictionaryFacilitator; - -@SuppressWarnings("unused") -public class ContextualDictionaryUpdater { - public ContextualDictionaryUpdater(final Context context, - final DictionaryFacilitator dictionaryFacilitator, - final Runnable onUpdateRunnable) { - } - - public void onLoadSettings(final boolean usePersonalizedDicts) { - } - - public void onStartInputView(final String packageName) { - } - - public void onDestroy() { - } -} diff --git a/java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java b/java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java deleted file mode 100644 index 64bace35a..000000000 --- a/java-overridable/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryUpdater.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import android.content.Context; - -import com.android.inputmethod.latin.DictionaryFacilitator; - -@SuppressWarnings("unused") -public class PersonalizationDictionaryUpdater { - final Context mContext; - final DictionaryFacilitator mDictionaryFacilitator; - boolean mDictCleared = false; - - public PersonalizationDictionaryUpdater(final Context context, - final DictionaryFacilitator dictionaryFacilitator) { - mContext = context; - mDictionaryFacilitator = dictionaryFacilitator; - } - - public void onLoadSettings(final boolean usePersonalizedDicts) { - if (!mDictCleared) { - // Clear and never update the personalization dictionary. - PersonalizationHelper.removeAllPersonalizationDictionaries(mContext); - mDictionaryFacilitator.clearPersonalizationDictionary(); - mDictCleared = true; - } - } - - public void onDestroy() { - } -} diff --git a/java/res/layout/suggestions_strip.xml b/java/res/layout/suggestions_strip.xml index aefdb8cad..47e9a918e 100644 --- a/java/res/layout/suggestions_strip.xml +++ b/java/res/layout/suggestions_strip.xml @@ -33,30 +33,6 @@ android:soundEffectsEnabled="false" /> <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings. We just need to ignore the system's audio and haptic feedback settings. --> - <LinearLayout - android:id="@+id/add_to_dictionary_strip" - android:orientation="horizontal" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_marginLeft="@dimen/config_suggestions_strip_horizontal_margin" - android:layout_marginRight="@dimen/config_suggestions_strip_horizontal_margin" - android:hapticFeedbackEnabled="false" - android:soundEffectsEnabled="false"> - <TextView - android:id="@+id/word_to_save" - android:layout_width="match_parent" - android:layout_height="match_parent" - style="?attr/suggestionWordStyle" /> - <include - android:id="@+id/word_to_save_divider" - layout="@layout/suggestion_divider" /> - <TextView - android:id="@+id/hint_add_to_dictionary" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:gravity="center_vertical|start" - style="?attr/suggestionWordStyle" /> - </LinearLayout> <!-- Provide audio and haptic feedback by ourselves based on the keyboard settings. We just need to ignore the system's audio and haptic feedback settings. --> <LinearLayout diff --git a/java/res/values/donottranslate-text-decorator.xml b/java/res/values/donottranslate-text-decorator.xml deleted file mode 100644 index 269364573..000000000 --- a/java/res/values/donottranslate-text-decorator.xml +++ /dev/null @@ -1,76 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -** -** Copyright 2014, 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. -*/ ---> - -<resources> - <!-- The extra margin in dp around the hit area of the commit/add-to-dictionary indicator --> - <integer name="text_decorator_hit_area_margin_in_dp"> - 4 - </integer> - - <!-- Background color to be used to highlight the target text when the add-to-dictionary - indicator is visible. --> - <color name="text_decorator_add_to_dictionary_indicator_text_highlight_color"> - #D1E7B7 - </color> - - <!-- Foreground color of the commit indicator. --> - <color name="text_decorator_add_to_dictionary_indicator_background_color"> - #4EB848 - </color> - - <!-- Foreground color of the add-to-dictionary indicator. --> - <color name="text_decorator_add_to_dictionary_indicator_foreground_color"> - #FFFFFF - </color> - - <!-- Viewport size of "text_decorator_add_to_dictionary_indicator_path". --> - <integer name="text_decorator_add_to_dictionary_indicator_path_size"> - 480 - </integer> - - <!-- Coordinates of the closed path to be used to render the add-to-dictionary indicator. - The format is: X[0], Y[0], X[1], Y[1], ..., X[N-1], Y[N-1] --> - <integer-array name="text_decorator_add_to_dictionary_indicator_path"> - <item>380</item> - <item>260</item> - <item>260</item> - <item>260</item> - <item>260</item> - <item>380</item> - <item>220</item> - <item>380</item> - <item>220</item> - <item>260</item> - <item>100</item> - <item>260</item> - <item>100</item> - <item>220</item> - <item>220</item> - <item>220</item> - <item>220</item> - <item>100</item> - <item>260</item> - <item>100</item> - <item>260</item> - <item>220</item> - <item>380</item> - <item>220</item> - </integer-array> -</resources> diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 9dc57e308..46476e29e 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -127,7 +127,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions, mKeyboardTextsSet.setLocale(mRichImm.getCurrentSubtypeLocales()[0], mThemeContext); } catch (KeyboardLayoutSetException e) { Log.w(TAG, "loading keyboard failed: " + e.mKeyboardId, e.getCause()); - return; } } diff --git a/java/src/com/android/inputmethod/keyboard/TextDecorator.java b/java/src/com/android/inputmethod/keyboard/TextDecorator.java deleted file mode 100644 index 892d36752..000000000 --- a/java/src/com/android/inputmethod/keyboard/TextDecorator.java +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (C) 2014 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.keyboard; - -import android.graphics.Matrix; -import android.graphics.RectF; -import android.inputmethodservice.InputMethodService; -import android.os.Message; -import android.text.TextUtils; -import android.util.Log; -import android.view.View; -import android.view.inputmethod.CursorAnchorInfo; - -import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; -import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; - -/** - * A controller class of the add-to-dictionary indicator (a.k.a. TextDecorator). This class - * is designed to be independent of UI subsystems such as {@link View}. All the UI related - * operations are delegated to {@link TextDecoratorUi} via {@link TextDecoratorUiOperator}. - */ -public class TextDecorator { - private static final String TAG = TextDecorator.class.getSimpleName(); - private static final boolean DEBUG = false; - - private static final int INVALID_CURSOR_INDEX = -1; - - private static final int MODE_MONITOR = 0; - private static final int MODE_WAITING_CURSOR_INDEX = 1; - private static final int MODE_SHOWING_INDICATOR = 2; - - private int mMode = MODE_MONITOR; - - private String mLastComposingText = null; - private boolean mHasRtlCharsInLastComposingText = false; - private RectF mComposingTextBoundsForLastComposingText = new RectF(); - - private boolean mIsFullScreenMode = false; - private String mWaitingWord = null; - private int mWaitingCursorStart = INVALID_CURSOR_INDEX; - private int mWaitingCursorEnd = INVALID_CURSOR_INDEX; - @Nullable - private CursorAnchorInfoCompatWrapper mCursorAnchorInfoWrapper = null; - - @Nonnull - private final Listener mListener; - - @Nonnull - private TextDecoratorUiOperator mUiOperator = EMPTY_UI_OPERATOR; - - public interface Listener { - /** - * Called when the user clicks the indicator to add the word into the dictionary. - * @param word the word which the user clicked on. - */ - void onClickComposingTextToAddToDictionary(final String word); - } - - public TextDecorator(@Nullable final Listener listener) { - mListener = (listener != null) ? listener : EMPTY_LISTENER; - } - - /** - * Sets the UI operator for {@link TextDecorator}. Any user visible operations will be - * delegated to the associated UI operator. - * @param uiOperator the UI operator to be associated. - */ - public void setUiOperator(@Nonnull final TextDecoratorUiOperator uiOperator) { - mUiOperator.disposeUi(); - mUiOperator = uiOperator; - mUiOperator.setOnClickListener(getOnClickHandler()); - } - - private final Runnable mDefaultOnClickHandler = new Runnable() { - @Override - public void run() { - onClickIndicator(); - } - }; - - @UsedForTesting - final Runnable getOnClickHandler() { - return mDefaultOnClickHandler; - } - - /** - * Shows the "Add to dictionary" indicator and associates it with associating the given word. - * - * @param word the word which should be associated with the indicator. This object will be - * passed back in {@link Listener#onClickComposingTextToAddToDictionary(String)}. - * @param selectionStart the cursor index (inclusive) when the indicator should be displayed. - * @param selectionEnd the cursor index (exclusive) when the indicator should be displayed. - */ - public void showAddToDictionaryIndicator(final String word, final int selectionStart, - final int selectionEnd) { - mWaitingWord = word; - mWaitingCursorStart = selectionStart; - mWaitingCursorEnd = selectionEnd; - mMode = MODE_WAITING_CURSOR_INDEX; - layoutLater(); - return; - } - - /** - * Must be called when the input method is about changing to for from the full screen mode. - * @param fullScreenMode {@code true} if the input method is entering the full screen mode. - * {@code false} is the input method is finishing the full screen mode. - */ - public void notifyFullScreenMode(final boolean fullScreenMode) { - final boolean fullScreenModeChanged = (mIsFullScreenMode != fullScreenMode); - mIsFullScreenMode = fullScreenMode; - if (fullScreenModeChanged) { - layoutLater(); - } - } - - /** - * Resets previous requests and makes indicator invisible. - */ - public void reset() { - mWaitingWord = null; - mMode = MODE_MONITOR; - mWaitingCursorStart = INVALID_CURSOR_INDEX; - mWaitingCursorEnd = INVALID_CURSOR_INDEX; - cancelLayoutInternalExpectedly("Resetting internal state."); - } - - /** - * Must be called when the {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} - * is called. - * - * <p>CAVEAT: Currently the input method author is responsible for ignoring - * {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} called in full screen - * mode.</p> - * @param info the compatibility wrapper object for the received {@link CursorAnchorInfo}. - */ - public void onUpdateCursorAnchorInfo(@Nullable final CursorAnchorInfoCompatWrapper info) { - mCursorAnchorInfoWrapper = info; - // Do not use layoutLater() to minimize the latency. - layoutImmediately(); - } - - private void cancelLayoutInternalUnexpectedly(final String message) { - mUiOperator.hideUi(); - Log.d(TAG, message); - } - - private void cancelLayoutInternalExpectedly(final String message) { - mUiOperator.hideUi(); - if (DEBUG) { - Log.d(TAG, message); - } - } - - private void layoutLater() { - mLayoutInvalidator.invalidateLayout(); - } - - - private void layoutImmediately() { - // Clear pending layout requests. - mLayoutInvalidator.cancelInvalidateLayout(); - layoutMain(); - } - - void layoutMain() { - final CursorAnchorInfoCompatWrapper info = mCursorAnchorInfoWrapper; - - if (info == null) { - cancelLayoutInternalExpectedly("CursorAnchorInfo isn't available."); - return; - } - - final Matrix matrix = info.getMatrix(); - if (matrix == null) { - cancelLayoutInternalUnexpectedly("Matrix is null"); - } - - final CharSequence composingText = info.getComposingText(); - if (!TextUtils.isEmpty(composingText)) { - final int composingTextStart = info.getComposingTextStart(); - final int lastCharRectIndex = composingTextStart + composingText.length() - 1; - final RectF lastCharRect = info.getCharacterBounds(lastCharRectIndex); - final int lastCharRectFlags = info.getCharacterBoundsFlags(lastCharRectIndex); - final boolean hasInvisibleRegionInLastCharRect = - (lastCharRectFlags & CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) - != 0; - if (lastCharRect == null || matrix == null || hasInvisibleRegionInLastCharRect) { - mUiOperator.hideUi(); - return; - } - - // Note that the following layout information is fragile, and must be invalidated - // even when surrounding text next to the composing text is changed because it can - // affect how the composing text is rendered. - // TODO: Investigate if we can change the input logic to make the target text - // composing state so that we can retrieve the character bounds reliably. - final String composingTextString = composingText.toString(); - final float top = lastCharRect.top; - final float bottom = lastCharRect.bottom; - float left = lastCharRect.left; - float right = lastCharRect.right; - boolean useRtlLayout = false; - for (int i = composingText.length() - 1; i >= 0; --i) { - final int characterIndex = composingTextStart + i; - final RectF characterBounds = info.getCharacterBounds(characterIndex); - final int characterBoundsFlags = info.getCharacterBoundsFlags(characterIndex); - if (characterBounds == null) { - break; - } - if (characterBounds.top != top) { - break; - } - if (characterBounds.bottom != bottom) { - break; - } - if ((characterBoundsFlags & CursorAnchorInfoCompatWrapper.FLAG_IS_RTL) != 0) { - // This is for both RTL text and bi-directional text. RTL languages usually mix - // RTL characters with LTR characters and in this case we should display the - // indicator on the left, while in LTR languages that normally never happens. - // TODO: Try to come up with a better algorithm. - useRtlLayout = true; - } - left = Math.min(characterBounds.left, left); - right = Math.max(characterBounds.right, right); - } - mLastComposingText = composingTextString; - mHasRtlCharsInLastComposingText = useRtlLayout; - mComposingTextBoundsForLastComposingText.set(left, top, right, bottom); - } - - final int selectionStart = info.getSelectionStart(); - final int selectionEnd = info.getSelectionEnd(); - switch (mMode) { - case MODE_MONITOR: - mUiOperator.hideUi(); - return; - case MODE_WAITING_CURSOR_INDEX: - if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) { - mUiOperator.hideUi(); - return; - } - mMode = MODE_SHOWING_INDICATOR; - break; - case MODE_SHOWING_INDICATOR: - if (selectionStart != mWaitingCursorStart || selectionEnd != mWaitingCursorEnd) { - mUiOperator.hideUi(); - mMode = MODE_MONITOR; - mWaitingCursorStart = INVALID_CURSOR_INDEX; - mWaitingCursorEnd = INVALID_CURSOR_INDEX; - return; - } - break; - default: - cancelLayoutInternalUnexpectedly("Unexpected internal mode=" + mMode); - return; - } - - if (!TextUtils.equals(mLastComposingText, mWaitingWord)) { - cancelLayoutInternalUnexpectedly("mLastComposingText doesn't match mWaitingWord"); - return; - } - - if ((info.getInsertionMarkerFlags() & - CursorAnchorInfoCompatWrapper.FLAG_HAS_INVISIBLE_REGION) != 0) { - mUiOperator.hideUi(); - return; - } - - mUiOperator.layoutUi(matrix, mComposingTextBoundsForLastComposingText, - mHasRtlCharsInLastComposingText); - } - - void onClickIndicator() { - if (mMode != MODE_SHOWING_INDICATOR) { - return; - } - mListener.onClickComposingTextToAddToDictionary(mWaitingWord); - } - - private final LayoutInvalidator mLayoutInvalidator = new LayoutInvalidator(this); - - /** - * Used for managing pending layout tasks for {@link TextDecorator#layoutLater()}. - */ - private static final class LayoutInvalidator { - private final HandlerImpl mHandler; - public LayoutInvalidator(@Nonnull final TextDecorator ownerInstance) { - mHandler = new HandlerImpl(ownerInstance); - } - - private static final int MSG_LAYOUT = 0; - - private static final class HandlerImpl - extends LeakGuardHandlerWrapper<TextDecorator> { - public HandlerImpl(@Nonnull final TextDecorator ownerInstance) { - super(ownerInstance); - } - - @Override - public void handleMessage(final Message msg) { - final TextDecorator owner = getOwnerInstance(); - if (owner == null) { - return; - } - switch (msg.what) { - case MSG_LAYOUT: - owner.layoutMain(); - break; - } - } - } - - /** - * Puts a layout task into the scheduler. Does nothing if one or more layout tasks are - * already scheduled. - */ - public void invalidateLayout() { - if (!mHandler.hasMessages(MSG_LAYOUT)) { - mHandler.obtainMessage(MSG_LAYOUT).sendToTarget(); - } - } - - /** - * Clears the pending layout tasks. - */ - public void cancelInvalidateLayout() { - mHandler.removeMessages(MSG_LAYOUT); - } - } - - @Nonnull - private final static Listener EMPTY_LISTENER = new Listener() { - @Override - public void onClickComposingTextToAddToDictionary(final String word) { - } - }; - - @Nonnull - private final static TextDecoratorUiOperator EMPTY_UI_OPERATOR = new TextDecoratorUiOperator() { - @Override - public void disposeUi() { - } - @Override - public void hideUi() { - } - @Override - public void setOnClickListener(Runnable listener) { - } - @Override - public void layoutUi(Matrix matrix, RectF composingTextBounds, boolean useRtlLayout) { - } - }; -} diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java deleted file mode 100644 index d87dc1bfa..000000000 --- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUi.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2014 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.keyboard; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; -import android.inputmethodservice.InputMethodService; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.Gravity; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.ViewParent; -import android.widget.PopupWindow; -import android.widget.RelativeLayout; - -import com.android.inputmethod.latin.R; - -/** - * Used as the UI component of {@link TextDecorator}. - */ -public final class TextDecoratorUi implements TextDecoratorUiOperator { - private static final boolean VISUAL_DEBUG = false; - private static final int VISUAL_DEBUG_HIT_AREA_COLOR = 0x80ff8000; - - private final RelativeLayout mLocalRootView; - private final AddToDictionaryIndicatorView mAddToDictionaryIndicatorView; - private final PopupWindow mTouchEventWindow; - private final View mTouchEventWindowClickListenerView; - private final float mHitAreaMarginInPixels; - private final RectF mDisplayRect; - - /** - * This constructor is designed to be called from {@link InputMethodService#setInputView(View)}. - * Other usages are not supported. - * - * @param context the context of the input method. - * @param inputView the view that is passed to {@link InputMethodService#setInputView(View)}. - */ - public TextDecoratorUi(final Context context, final View inputView) { - final Resources resources = context.getResources(); - final int hitAreaMarginInDP = resources.getInteger( - R.integer.text_decorator_hit_area_margin_in_dp); - mHitAreaMarginInPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, - hitAreaMarginInDP, resources.getDisplayMetrics()); - final DisplayMetrics displayMetrics = resources.getDisplayMetrics(); - mDisplayRect = new RectF(0.0f, 0.0f, displayMetrics.widthPixels, - displayMetrics.heightPixels); - - mLocalRootView = new RelativeLayout(context); - mLocalRootView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, - LayoutParams.MATCH_PARENT)); - // TODO: Use #setBackground(null) for API Level >= 16. - mLocalRootView.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); - - final ViewGroup contentView = getContentView(inputView); - mAddToDictionaryIndicatorView = new AddToDictionaryIndicatorView(context); - mLocalRootView.addView(mAddToDictionaryIndicatorView); - if (contentView != null) { - contentView.addView(mLocalRootView); - } - - // This popup window is used to avoid the limitation that the input method is not able to - // observe the touch events happening outside of InputMethodService.Insets#touchableRegion. - // We don't use this popup window for rendering the UI for performance reasons though. - mTouchEventWindow = new PopupWindow(context); - if (VISUAL_DEBUG) { - mTouchEventWindow.setBackgroundDrawable(new ColorDrawable(VISUAL_DEBUG_HIT_AREA_COLOR)); - } else { - mTouchEventWindow.setBackgroundDrawable(null); - } - mTouchEventWindowClickListenerView = new View(context); - mTouchEventWindow.setContentView(mTouchEventWindowClickListenerView); - } - - @Override - public void disposeUi() { - if (mLocalRootView != null) { - final ViewParent parent = mLocalRootView.getParent(); - if (parent != null && parent instanceof ViewGroup) { - ((ViewGroup) parent).removeView(mLocalRootView); - } - mLocalRootView.removeAllViews(); - } - if (mTouchEventWindow != null) { - mTouchEventWindow.dismiss(); - } - } - - @Override - public void hideUi() { - mAddToDictionaryIndicatorView.setVisibility(View.GONE); - mTouchEventWindow.dismiss(); - } - - private static final RectF getIndicatorBoundsInScreenCoordinates(final Matrix matrix, - final RectF composingTextBounds, final boolean showAtLeftSide) { - final float indicatorSize = composingTextBounds.height(); - final RectF indicatorBounds; - if (showAtLeftSide) { - indicatorBounds = new RectF(composingTextBounds.left - indicatorSize, - composingTextBounds.top, composingTextBounds.left, - composingTextBounds.top + indicatorSize); - } else { - indicatorBounds = new RectF(composingTextBounds.right, composingTextBounds.top, - composingTextBounds.right + indicatorSize, - composingTextBounds.top + indicatorSize); - } - matrix.mapRect(indicatorBounds); - return indicatorBounds; - } - - @Override - public void layoutUi(final Matrix matrix, final RectF composingTextBounds, - final boolean useRtlLayout) { - RectF indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix, - composingTextBounds, useRtlLayout /* showAtLeftSide */); - if (indicatorBoundsInScreenCoordinates.left < mDisplayRect.left || - mDisplayRect.right < indicatorBoundsInScreenCoordinates.right) { - // The indicator is clipped by the screen. Show the indicator at the opposite side. - indicatorBoundsInScreenCoordinates = getIndicatorBoundsInScreenCoordinates(matrix, - composingTextBounds, !useRtlLayout /* showAtLeftSide */); - } - - mAddToDictionaryIndicatorView.setBounds(indicatorBoundsInScreenCoordinates); - - final RectF hitAreaBoundsInScreenCoordinates = new RectF(); - matrix.mapRect(hitAreaBoundsInScreenCoordinates, composingTextBounds); - hitAreaBoundsInScreenCoordinates.union(indicatorBoundsInScreenCoordinates); - hitAreaBoundsInScreenCoordinates.inset(-mHitAreaMarginInPixels, -mHitAreaMarginInPixels); - - final int[] originScreen = new int[2]; - mLocalRootView.getLocationOnScreen(originScreen); - final int viewOriginX = originScreen[0]; - final int viewOriginY = originScreen[1]; - mAddToDictionaryIndicatorView.setX(indicatorBoundsInScreenCoordinates.left - viewOriginX); - mAddToDictionaryIndicatorView.setY(indicatorBoundsInScreenCoordinates.top - viewOriginY); - mAddToDictionaryIndicatorView.setVisibility(View.VISIBLE); - - if (mTouchEventWindow.isShowing()) { - mTouchEventWindow.update((int)hitAreaBoundsInScreenCoordinates.left - viewOriginX, - (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY, - (int)hitAreaBoundsInScreenCoordinates.width(), - (int)hitAreaBoundsInScreenCoordinates.height()); - } else { - mTouchEventWindow.setWidth((int)hitAreaBoundsInScreenCoordinates.width()); - mTouchEventWindow.setHeight((int)hitAreaBoundsInScreenCoordinates.height()); - mTouchEventWindow.showAtLocation(mLocalRootView, Gravity.NO_GRAVITY, - (int)hitAreaBoundsInScreenCoordinates.left - viewOriginX, - (int)hitAreaBoundsInScreenCoordinates.top - viewOriginY); - } - } - - @Override - public void setOnClickListener(final Runnable listener) { - mTouchEventWindowClickListenerView.setOnClickListener(new OnClickListener() { - @Override - public void onClick(final View arg0) { - listener.run(); - } - }); - } - - private static class IndicatorView extends View { - private final Path mPath; - private final Path mTmpPath = new Path(); - private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Matrix mMatrix = new Matrix(); - private final int mBackgroundColor; - private final int mForegroundColor; - private final RectF mBounds = new RectF(); - public IndicatorView(Context context, final int pathResourceId, - final int sizeResourceId, final int backgroundColorResourceId, - final int foregroundColroResourceId) { - super(context); - final Resources resources = context.getResources(); - mPath = createPath(resources, pathResourceId, sizeResourceId); - mBackgroundColor = resources.getColor(backgroundColorResourceId); - mForegroundColor = resources.getColor(foregroundColroResourceId); - } - - public void setBounds(final RectF rect) { - mBounds.set(rect); - } - - @Override - protected void onDraw(Canvas canvas) { - mPaint.setColor(mBackgroundColor); - mPaint.setStyle(Paint.Style.FILL); - canvas.drawRect(0.0f, 0.0f, mBounds.width(), mBounds.height(), mPaint); - - mMatrix.reset(); - mMatrix.postScale(mBounds.width(), mBounds.height()); - mPath.transform(mMatrix, mTmpPath); - mPaint.setColor(mForegroundColor); - canvas.drawPath(mTmpPath, mPaint); - } - - private static Path createPath(final Resources resources, final int pathResourceId, - final int sizeResourceId) { - final int size = resources.getInteger(sizeResourceId); - final float normalizationFactor = 1.0f / size; - final int[] array = resources.getIntArray(pathResourceId); - - final Path path = new Path(); - for (int i = 0; i < array.length; i += 2) { - if (i == 0) { - path.moveTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor); - } else { - path.lineTo(array[i] * normalizationFactor, array[i + 1] * normalizationFactor); - } - } - path.close(); - return path; - } - } - - private static ViewGroup getContentView(final View view) { - final View rootView = view.getRootView(); - if (rootView == null) { - return null; - } - - final ViewGroup windowContentView = (ViewGroup)rootView.findViewById(android.R.id.content); - if (windowContentView == null) { - return null; - } - return windowContentView; - } - - private static final class AddToDictionaryIndicatorView extends TextDecoratorUi.IndicatorView { - public AddToDictionaryIndicatorView(final Context context) { - super(context, R.array.text_decorator_add_to_dictionary_indicator_path, - R.integer.text_decorator_add_to_dictionary_indicator_path_size, - R.color.text_decorator_add_to_dictionary_indicator_background_color, - R.color.text_decorator_add_to_dictionary_indicator_foreground_color); - } - } -}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java b/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java deleted file mode 100644 index 9e30e417e..000000000 --- a/java/src/com/android/inputmethod/keyboard/TextDecoratorUiOperator.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2014 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.keyboard; - -import android.graphics.Matrix; -import android.graphics.RectF; - -/** - * This interface defines how UI operations required for {@link TextDecorator} are delegated to - * the actual UI implementation class. - */ -public interface TextDecoratorUiOperator { - /** - * Called to notify that the UI is ready to be disposed. - */ - void disposeUi(); - - /** - * Called when the UI should become invisible. - */ - void hideUi(); - - /** - * Called to set the new click handler. - * @param onClickListener the callback object whose {@link Runnable#run()} should be called when - * the indicator is clicked. - */ - void setOnClickListener(final Runnable onClickListener); - - /** - * Called when the layout should be updated. - * @param matrix The matrix that transforms the local coordinates into the screen coordinates. - * @param composingTextBounds The bounding box of the composing text, in local coordinates. - * @param useRtlLayout {@code true} if the indicator should be optimized for RTL layout. - */ - void layoutUi(final Matrix matrix, final RectF composingTextBounds, final boolean useRtlLayout); -} diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java index cf4dd3db3..f4c4f1aab 100644 --- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiPalettesView.java @@ -22,7 +22,6 @@ import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; -import android.os.CountDownTimer; import android.preference.PreferenceManager; import android.support.v4.view.ViewPager; import android.util.AttributeSet; @@ -52,8 +51,6 @@ import com.android.inputmethod.latin.RichInputMethodSubtype; import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.utils.ResourceUtils; -import java.util.concurrent.TimeUnit; - /** * View class to implement Emoji palettes. * The Emoji keyboard consists of group of views layout/emoji_palettes_view. @@ -75,9 +72,9 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange private final int mCategoryIndicatorBackgroundResId; private final int mCategoryPageIndicatorColor; private final int mCategoryPageIndicatorBackground; - private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; private EmojiPalettesAdapter mEmojiPalettesAdapter; private final EmojiLayoutParams mEmojiLayoutParams; + private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; private ImageButton mDeleteKey; private TextView mAlphabetKeyLeft; @@ -132,7 +129,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange mCategoryPageIndicatorBackground = emojiPalettesViewAttr.getColor( R.styleable.EmojiPalettesView_categoryPageIndicatorBackground, 0); emojiPalettesViewAttr.recycle(); - mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(context); + mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(); } @Override @@ -265,7 +262,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange @Override public void onPageScrolled(final int position, final float positionOffset, - final int positionOffsetPixels) { + final int positionOffsetPixels) { mEmojiPalettesAdapter.onPageScrolled(); final Pair<Integer, Integer> newPos = mEmojiCategory.getCategoryIdAndPageIdFromPagePosition(position); @@ -364,7 +361,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } private static void setupAlphabetKey(final TextView alphabetKey, final String label, - final KeyDrawParams params) { + final KeyDrawParams params) { alphabetKey.setText(label); alphabetKey.setTextColor(params.mFunctionalTextColor); alphabetKey.setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize); @@ -372,7 +369,8 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } public void startEmojiPalettes(final String switchToAlphaLabel, - final KeyVisualAttributes keyVisualAttr, final KeyboardIconsSet iconSet) { + final KeyVisualAttributes keyVisualAttr, + final KeyboardIconsSet iconSet) { final int deleteIconResId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_DELETE_KEY); if (deleteIconResId != 0) { mDeleteKey.setImageResource(deleteIconResId); @@ -398,7 +396,7 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange public void setKeyboardActionListener(final KeyboardActionListener listener) { mKeyboardActionListener = listener; - mDeleteKeyOnTouchListener.setKeyboardActionListener(mKeyboardActionListener); + mDeleteKeyOnTouchListener.setKeyboardActionListener(listener); } private void updateEmojiCategoryPageIdView() { @@ -436,45 +434,9 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange } private static class DeleteKeyOnTouchListener implements OnTouchListener { - static final long MAX_REPEAT_COUNT_TIME = TimeUnit.SECONDS.toMillis(30); - final long mKeyRepeatStartTimeout; - final long mKeyRepeatInterval; - - public DeleteKeyOnTouchListener(Context context) { - final Resources res = context.getResources(); - mKeyRepeatStartTimeout = res.getInteger(R.integer.config_key_repeat_start_timeout); - mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); - mTimer = new CountDownTimer(MAX_REPEAT_COUNT_TIME, mKeyRepeatInterval) { - @Override - public void onTick(long millisUntilFinished) { - final long elapsed = MAX_REPEAT_COUNT_TIME - millisUntilFinished; - if (elapsed < mKeyRepeatStartTimeout) { - return; - } - onKeyRepeat(); - } - @Override - public void onFinish() { - onKeyRepeat(); - } - }; - } - - /** Key-repeat state. */ - private static final int KEY_REPEAT_STATE_INITIALIZED = 0; - // The key is touched but auto key-repeat is not started yet. - private static final int KEY_REPEAT_STATE_KEY_DOWN = 1; - // At least one key-repeat event has already been triggered and the key is not released. - private static final int KEY_REPEAT_STATE_KEY_REPEAT = 2; - private KeyboardActionListener mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER; - // TODO: Do the same things done in PointerTracker - private final CountDownTimer mTimer; - private int mState = KEY_REPEAT_STATE_INITIALIZED; - private int mRepeatCount = 0; - public void setKeyboardActionListener(final KeyboardActionListener listener) { mKeyboardActionListener = listener; } @@ -482,79 +444,40 @@ public final class EmojiPalettesView extends LinearLayout implements OnTabChange @Override public boolean onTouch(final View v, final MotionEvent event) { switch (event.getActionMasked()) { - case MotionEvent.ACTION_DOWN: - onTouchDown(v); - return true; - case MotionEvent.ACTION_MOVE: - final float x = event.getX(); - final float y = event.getY(); - if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) { - // Stop generating key events once the finger moves away from the view area. - onTouchCanceled(v); - } - return true; - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_UP: - onTouchUp(v); - return true; + case MotionEvent.ACTION_DOWN: + onTouchDown(v); + return true; + case MotionEvent.ACTION_MOVE: + final float x = event.getX(); + final float y = event.getY(); + if (x < 0.0f || v.getWidth() < x || y < 0.0f || v.getHeight() < y) { + // Stop generating key events once the finger moves away from the view area. + onTouchCanceled(v); + } + return true; + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + onTouchUp(v); + return true; } return false; } - private void handleKeyDown() { - mKeyboardActionListener.onPressKey( - Constants.CODE_DELETE, mRepeatCount, true /* isSinglePointer */); - } - - private void handleKeyUp() { - mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE, - NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */); - mKeyboardActionListener.onReleaseKey( - Constants.CODE_DELETE, false /* withSliding */); - ++mRepeatCount; - } - private void onTouchDown(final View v) { - mTimer.cancel(); - mRepeatCount = 0; - handleKeyDown(); + mKeyboardActionListener.onPressKey(Constants.CODE_DELETE, + 0 /* repeatCount */, true /* isSinglePointer */); v.setPressed(true /* pressed */); - mState = KEY_REPEAT_STATE_KEY_DOWN; - mTimer.start(); } private void onTouchUp(final View v) { - mTimer.cancel(); - if (mState == KEY_REPEAT_STATE_KEY_DOWN) { - handleKeyUp(); - } + mKeyboardActionListener.onCodeInput(Constants.CODE_DELETE, + NOT_A_COORDINATE, NOT_A_COORDINATE, false /* isKeyRepeat */); + mKeyboardActionListener.onReleaseKey(Constants.CODE_DELETE, false /* withSliding */); v.setPressed(false /* pressed */); - mState = KEY_REPEAT_STATE_INITIALIZED; } private void onTouchCanceled(final View v) { - mTimer.cancel(); v.setBackgroundColor(Color.TRANSPARENT); - mState = KEY_REPEAT_STATE_INITIALIZED; - } - - // Called by {@link #mTimer} in the UI thread as an auto key-repeat signal. - void onKeyRepeat() { - switch (mState) { - case KEY_REPEAT_STATE_INITIALIZED: - // Basically this should not happen. - break; - case KEY_REPEAT_STATE_KEY_DOWN: - // Do not call {@link #handleKeyDown} here because it has already been called - // in {@link #onTouchDown}. - handleKeyUp(); - mState = KEY_REPEAT_STATE_KEY_REPEAT; - break; - case KEY_REPEAT_STATE_KEY_REPEAT: - handleKeyDown(); - handleKeyUp(); - break; - } } } -} +}
\ No newline at end of file diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index b0eae0832..7e4d66583 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -27,6 +27,7 @@ import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.FileUtils; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; @@ -319,9 +320,9 @@ public final class BinaryDictionary extends Dictionary { final int count = session.mOutputSuggestionCount[0]; final ArrayList<SuggestedWordInfo> suggestions = new ArrayList<>(); for (int j = 0; j < count; ++j) { - final int start = j * Constants.DICTIONARY_MAX_WORD_LENGTH; + final int start = j * DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; int len = 0; - while (len < Constants.DICTIONARY_MAX_WORD_LENGTH + while (len < DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH && session.mOutputCodePoints[start + len] != 0) { ++len; } @@ -390,7 +391,7 @@ public final class BinaryDictionary extends Dictionary { return null; } final int[] codePoints = StringUtils.toCodePointArray(word); - final int[] outCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; + final int[] outCodePoints = new int[DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH]; final boolean[] outFlags = new boolean[FORMAT_WORD_PROPERTY_OUTPUT_FLAG_COUNT]; final int[] outProbabilityInfo = new int[FORMAT_WORD_PROPERTY_OUTPUT_PROBABILITY_INFO_COUNT]; @@ -431,7 +432,7 @@ public final class BinaryDictionary extends Dictionary { * If token is 0, this method newly starts iterating the dictionary. */ public GetNextWordPropertyResult getNextWordProperty(final int token) { - final int[] codePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; + final int[] codePoints = new int[DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH]; final boolean[] isBeginningOfSentence = new boolean[1]; final int nextToken = getNextWordNative(mNativeDict, token, codePoints, isBeginningOfSentence); diff --git a/java/src/com/android/inputmethod/latin/DicTraverseSession.java b/java/src/com/android/inputmethod/latin/DicTraverseSession.java index e7fd99ee8..6816f129a 100644 --- a/java/src/com/android/inputmethod/latin/DicTraverseSession.java +++ b/java/src/com/android/inputmethod/latin/DicTraverseSession.java @@ -16,8 +16,8 @@ package com.android.inputmethod.latin; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.NativeSuggestOptions; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.utils.JniUtils; import java.util.Locale; @@ -28,14 +28,15 @@ public final class DicTraverseSession { } // Must be equal to MAX_RESULTS in native/jni/src/defines.h private static final int MAX_RESULTS = 18; - public final int[] mInputCodePoints = new int[Constants.DICTIONARY_MAX_WORD_LENGTH]; + public final int[] mInputCodePoints = + new int[DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH]; public final int[][] mPrevWordCodePointArrays = - new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][]; + new int[DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][]; public final boolean[] mIsBeginningOfSentenceArray = - new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + new boolean[DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; public final int[] mOutputSuggestionCount = new int[1]; public final int[] mOutputCodePoints = - new int[Constants.DICTIONARY_MAX_WORD_LENGTH * MAX_RESULTS]; + new int[DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH * MAX_RESULTS]; public final int[] mSpaceIndices = new int[MAX_RESULTS]; public final int[] mOutputScores = new int[MAX_RESULTS]; public final int[] mOutputTypes = new int[MAX_RESULTS]; diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index 7d7ed77e7..16dcb3208 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -49,8 +49,7 @@ public abstract class Dictionary { // Spawned by resuming suggestions. Comes from a span that was in the TextView. public static final String TYPE_RESUMED = "resumed"; - public static final PhonyDictionary DICTIONARY_RESUMED = - new PhonyDictionary(TYPE_RESUMED); + public static final PhonyDictionary DICTIONARY_RESUMED = new PhonyDictionary(TYPE_RESUMED); // The following types of dictionary have actual functional instances. We don't need final // phony dictionary instances for them. @@ -60,10 +59,6 @@ public abstract class Dictionary { public static final String TYPE_USER = "user"; // User history dictionary internal to LatinIME. public static final String TYPE_USER_HISTORY = "history"; - // Personalization dictionary. - public static final String TYPE_PERSONALIZATION = "personalization"; - // Contextual dictionary. - public static final String TYPE_CONTEXTUAL = "contextual"; public final String mDictType; // The locale for this dictionary. May be null if unknown (phony dictionary for example). public final Locale mLocale; @@ -76,9 +71,7 @@ public abstract class Dictionary { TYPE_USER_TYPED, TYPE_USER, TYPE_CONTACTS, - TYPE_USER_HISTORY, - TYPE_PERSONALIZATION, - TYPE_CONTEXTUAL)); + TYPE_USER_HISTORY)); public Dictionary(final String dictType, final Locale locale) { mDictType = dictType; diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java index a0a1d939e..3e4cda47a 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitator.java @@ -17,21 +17,19 @@ package com.android.inputmethod.latin; import android.content.Context; -import android.view.inputmethod.InputMethodSubtype; import android.util.Pair; +import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback; -import com.android.inputmethod.latin.personalization.PersonalizationDataChunk; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; -import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.SuggestionResults; import java.io.File; import java.util.ArrayList; import java.util.HashMap; -import java.util.Locale; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; @@ -45,6 +43,35 @@ import javax.annotation.Nullable; * DictionaryFacilitator as a client for interacting with dictionaries. */ public interface DictionaryFacilitator { + + public static final String[] ALL_DICTIONARY_TYPES = new String[] { + Dictionary.TYPE_MAIN, + Dictionary.TYPE_USER_HISTORY, + Dictionary.TYPE_USER, + Dictionary.TYPE_CONTACTS}; + + public static final String[] DYNAMIC_DICTIONARY_TYPES = new String[] { + Dictionary.TYPE_USER_HISTORY, + Dictionary.TYPE_USER, + Dictionary.TYPE_CONTACTS}; + + /** + * {@link Dictionary#TYPE_USER} is deprecated, except for the spelling service. + */ + public static final String[] DICTIONARY_TYPES_FOR_SPELLING = new String[] { + Dictionary.TYPE_MAIN, + Dictionary.TYPE_USER_HISTORY, + Dictionary.TYPE_USER, + Dictionary.TYPE_CONTACTS}; + + /** + * {@link Dictionary#TYPE_USER} is deprecated, except for the spelling service. + */ + public static final String[] DICTIONARY_TYPES_FOR_SUGGESTIONS = new String[] { + Dictionary.TYPE_MAIN, + Dictionary.TYPE_USER_HISTORY, + Dictionary.TYPE_CONTACTS}; + /** * Returns whether this facilitator is exactly for this list of locales. * @@ -86,24 +113,22 @@ public interface DictionaryFacilitator { boolean isConfidentAboutCurrentLanguageBeing(final Locale mLocale); - void resetDictionaries(final Context context, final Locale[] newLocales, - final boolean useContactsDict, final boolean usePersonalizedDicts, - final boolean forceReloadMainDictionary, - @Nullable final String account, - final DictionaryInitializationListener listener); - - void resetDictionariesWithDictNamePrefix(final Context context, + void resetDictionaries( + final Context context, final Locale[] newLocales, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, - @Nullable final DictionaryInitializationListener listener, + @Nullable final String account, final String dictNamePrefix, - @Nullable final String account); + @Nullable final DictionaryInitializationListener listener); @UsedForTesting - void resetDictionariesForTesting(final Context context, final Locale[] locales, - final ArrayList<String> dictionaryTypes, final HashMap<String, File> dictionaryFiles, + void resetDictionariesForTesting( + final Context context, + final Locale[] locales, + final ArrayList<String> dictionaryTypes, + final HashMap<String, File> dictionaryFiles, final Map<String, Map<String, String>> additionalDictAttributes, @Nullable final String account); @@ -118,10 +143,6 @@ public interface DictionaryFacilitator { boolean hasAtLeastOneUninitializedMainDictionary(); - boolean hasPersonalizationDictionary(); - - void flushPersonalizationDictionary(); - void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit) throws InterruptedException; @@ -129,10 +150,6 @@ public interface DictionaryFacilitator { void waitForLoadingDictionariesForTesting(final long timeout, final TimeUnit unit) throws InterruptedException; - boolean isUserDictionaryEnabled(); - - void addWordToUserDictionary(final Context context, final String word); - void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, @Nonnull final NgramContext ngramContext, final int timeStampInSeconds, final boolean blockPotentiallyOffensive); @@ -142,9 +159,12 @@ public interface DictionaryFacilitator { // TODO: Revise the way to fusion suggestion results. SuggestionResults getSuggestionResults(final WordComposer composer, final NgramContext ngramContext, final long proximityInfoHandle, - final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId); + final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId, + final int inputStyle, final KeyboardLayout keyboardLayout); + + boolean isValidSpellingWord(final String word); - boolean isValidWord(final String word, final boolean ignoreCase); + boolean isValidSuggestionWord(final String word); int getFrequency(final String word); @@ -152,21 +172,6 @@ public interface DictionaryFacilitator { void clearUserHistoryDictionary(); - // This method gets called only when the IME receives a notification to remove the - // personalization dictionary. - void clearPersonalizationDictionary(); - - void clearContextualDictionary(); - - void addEntriesToPersonalizationDictionary( - final PersonalizationDataChunk personalizationDataChunk, - final SpacingAndPunctuations spacingAndPunctuations, - final UpdateEntriesForInputEventsCallback callback); - - @UsedForTesting - void addPhraseToContextualDictionary(final String[] phrase, final int probability, - final int bigramProbabilityForWords, final int bigramProbabilityForPhrases); - void dumpDictionaryForDebug(final String dictName); ArrayList<Pair<String, DictionaryStats>> getStatsOfEnabledSubDicts(); diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java index 167501118..dd34faef8 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorImpl.java @@ -23,16 +23,12 @@ import android.util.Pair; import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.latin.NgramContext.WordInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; -import com.android.inputmethod.latin.personalization.ContextualDictionary; -import com.android.inputmethod.latin.personalization.PersonalizationDataChunk; -import com.android.inputmethod.latin.personalization.PersonalizationDictionary; import com.android.inputmethod.latin.personalization.UserHistoryDictionary; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; -import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.DistracterFilter; import com.android.inputmethod.latin.utils.DistracterFilterCheckingExactMatchesAndSuggestions; import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary; @@ -43,7 +39,6 @@ import java.io.File; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -78,42 +73,24 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { private DictionaryGroup[] mDictionaryGroups = new DictionaryGroup[] { new DictionaryGroup() }; private DictionaryGroup mMostProbableDictionaryGroup = mDictionaryGroups[0]; - private boolean mIsUserDictEnabled = false; private volatile CountDownLatch mLatchForWaitingLoadingMainDictionaries = new CountDownLatch(0); // To synchronize assigning mDictionaryGroup to ensure closing dictionaries. private final Object mLock = new Object(); private final DistracterFilter mDistracterFilter; - private final PersonalizationHelperForDictionaryFacilitator mPersonalizationHelper; - - private static final String[] DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS = - new String[] { - Dictionary.TYPE_MAIN, - Dictionary.TYPE_USER_HISTORY, - Dictionary.TYPE_PERSONALIZATION, - Dictionary.TYPE_USER, - Dictionary.TYPE_CONTACTS, - Dictionary.TYPE_CONTEXTUAL - }; public static final Map<String, Class<? extends ExpandableBinaryDictionary>> DICT_TYPE_TO_CLASS = new HashMap<>(); static { DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER_HISTORY, UserHistoryDictionary.class); - DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_PERSONALIZATION, PersonalizationDictionary.class); DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_USER, UserBinaryDictionary.class); DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTACTS, ContactsBinaryDictionary.class); - DICT_TYPE_TO_CLASS.put(Dictionary.TYPE_CONTEXTUAL, ContextualDictionary.class); } private static final String DICT_FACTORY_METHOD_NAME = "getDictionary"; private static final Class<?>[] DICT_FACTORY_METHOD_ARG_TYPES = new Class[] { Context.class, Locale.class, File.class, String.class, String.class }; - private static final String[] SUB_DICT_TYPES = - Arrays.copyOfRange(DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS, 1 /* start */, - DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS.length); - /** * Returns whether this facilitator is exactly for this list of locales. * @@ -257,23 +234,18 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { public DictionaryFacilitatorImpl() { mDistracterFilter = DistracterFilter.EMPTY_DISTRACTER_FILTER; - mPersonalizationHelper = null; } public DictionaryFacilitatorImpl(final Context context) { mDistracterFilter = new DistracterFilterCheckingExactMatchesAndSuggestions(context); - mPersonalizationHelper = - new PersonalizationHelperForDictionaryFacilitator(context, mDistracterFilter); } public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) { mDistracterFilter.updateEnabledSubtypes(enabledSubtypes); - mPersonalizationHelper.updateEnabledSubtypes(enabledSubtypes); } // TODO: remove this, it's confusing with seamless multiple language switching public void setIsMonolingualUser(final boolean isMonolingualUser) { - mPersonalizationHelper.setIsMonolingualUser(isMonolingualUser); } public boolean isActive() { @@ -370,16 +342,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } } - public void resetDictionaries(final Context context, final Locale[] newLocales, - final boolean useContactsDict, final boolean usePersonalizedDicts, - final boolean forceReloadMainDictionary, - @Nullable final String account, - final DictionaryInitializationListener listener) { - resetDictionariesWithDictNamePrefix(context, newLocales, useContactsDict, - usePersonalizedDicts, forceReloadMainDictionary, listener, "" /* dictNamePrefix */, - account); - } - @Nullable static DictionaryGroup findDictionaryGroupWithLocale(final DictionaryGroup[] dictionaryGroups, final Locale locale) { @@ -391,14 +353,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { return null; } - public void resetDictionariesWithDictNamePrefix(final Context context, + public void resetDictionaries( + final Context context, final Locale[] newLocales, final boolean useContactsDict, final boolean usePersonalizedDicts, final boolean forceReloadMainDictionary, - @Nullable final DictionaryInitializationListener listener, + @Nullable final String account, final String dictNamePrefix, - @Nullable final String account) { + @Nullable final DictionaryInitializationListener listener) { final HashMap<Locale, ArrayList<String>> existingDictionariesToCleanup = new HashMap<>(); // TODO: Make subDictTypesToUse configurable by resource or a static final list. final HashSet<String> subDictTypesToUse = new HashSet<>(); @@ -408,8 +371,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } if (usePersonalizedDicts) { subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY); - subDictTypesToUse.add(Dictionary.TYPE_PERSONALIZATION); - subDictTypesToUse.add(Dictionary.TYPE_CONTEXTUAL); } // Gather all dictionaries. We'll remove them from the list to clean up later. @@ -421,7 +382,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { if (null == currentDictionaryGroupForLocale) { continue; } - for (final String dictType : SUB_DICT_TYPES) { + for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { if (currentDictionaryGroupForLocale.hasDict(dictType, account)) { dictTypeForLocale.add(dictType); } @@ -473,7 +434,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { oldDictionaryGroups = mDictionaryGroups; mDictionaryGroups = newDictionaryGroups; mMostProbableDictionaryGroup = newDictionaryGroups[0]; - mIsUserDictEnabled = UserBinaryDictionary.isEnabled(context); if (hasAtLeastOneUninitializedMainDictionary()) { asyncReloadUninitializedMainDictionaries(context, newLocales, listener); } @@ -581,14 +541,11 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { mDictionaryGroups = new DictionaryGroup[] { mMostProbableDictionaryGroup }; } for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) { + for (final String dictType : ALL_DICTIONARY_TYPES) { dictionaryGroup.closeDict(dictType); } } mDistracterFilter.close(); - if (mPersonalizationHelper != null) { - mPersonalizationHelper.close(); - } } @UsedForTesting @@ -620,30 +577,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { return false; } - public boolean hasPersonalizationDictionary() { - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - if (dictionaryGroup.hasDict(Dictionary.TYPE_PERSONALIZATION, null /* account */)) { - return true; - } - } - return false; - } - - public void flushPersonalizationDictionary() { - final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion = - new HashSet<>(); - final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; - for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - final ExpandableBinaryDictionary personalizationDictUsedForSuggestion = - dictionaryGroup.getSubDict(Dictionary.TYPE_PERSONALIZATION); - personalizationDictsUsedForSuggestion.add(personalizationDictUsedForSuggestion); - } - mPersonalizationHelper.flushPersonalizationDictionariesToUpdate( - personalizationDictsUsedForSuggestion); - mDistracterFilter.close(); - } - public void waitForLoadingMainDictionaries(final long timeout, final TimeUnit unit) throws InterruptedException { mLatchForWaitingLoadingMainDictionaries.await(timeout, unit); @@ -661,19 +594,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { } } - public boolean isUserDictionaryEnabled() { - return mIsUserDictEnabled; - } - - public void addWordToUserDictionary(final Context context, final String word) { - final Locale locale = getMostProbableLocale(); - if (locale == null) { - return; - } - // TODO: add a toast telling what language this is being added to? - UserBinaryDictionary.addWordToUserDictionary(context, locale, word); - } - public void addToUserHistory(final String suggestion, final boolean wasAutoCapitalized, @Nonnull final NgramContext ngramContext, final int timeStampInSeconds, final boolean blockPotentiallyOffensive) { @@ -706,8 +626,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale); final String secondWord; if (wasAutoCapitalized) { - if (isValidWord(word, false /* ignoreCase */) - && !isValidWord(lowerCasedWord, false /* ignoreCase */)) { + if (isValidSuggestionWord(word) && !isValidSuggestionWord(lowerCasedWord)) { // If the word was auto-capitalized and exists only as a capitalized word in the // dictionary, then we must not downcase it before registering it. For example, // the name of the contacts in start-of-sentence position would come here with the @@ -755,21 +674,21 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { public void removeWordFromPersonalizedDicts(final String word) { removeWord(Dictionary.TYPE_USER_HISTORY, word); - removeWord(Dictionary.TYPE_PERSONALIZATION, word); - removeWord(Dictionary.TYPE_CONTEXTUAL, word); } // TODO: Revise the way to fusion suggestion results. - public SuggestionResults getSuggestionResults(final WordComposer composer, - final NgramContext ngramContext, final long proximityInfoHandle, - final SettingsValuesForSuggestion settingsValuesForSuggestion, final int sessionId) { + @Override + public SuggestionResults getSuggestionResults(WordComposer composer, + NgramContext ngramContext, long proximityInfoHandle, + SettingsValuesForSuggestion settingsValuesForSuggestion, int sessionId, + int inputStyle, KeyboardLayout keyboardLayout) { final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; final SuggestionResults suggestionResults = new SuggestionResults( SuggestedWords.MAX_SUGGESTIONS, ngramContext.isBeginningOfSentenceContext()); final float[] weightOfLangModelVsSpatialModel = new float[] { Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL }; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) { + for (final String dictType : DICTIONARY_TYPES_FOR_SUGGESTIONS) { final Dictionary dictionary = dictionaryGroup.getDict(dictType); if (null == dictionary) continue; final float weightForLocale = composer.isBatchMode() @@ -789,7 +708,15 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { return suggestionResults; } - public boolean isValidWord(final String word, final boolean ignoreCase) { + public boolean isValidSpellingWord(final String word) { + return isValidWord(word, DICTIONARY_TYPES_FOR_SPELLING); + } + + public boolean isValidSuggestionWord(final String word) { + return isValidWord(word, DICTIONARY_TYPES_FOR_SUGGESTIONS); + } + + private boolean isValidWord(final String word, final String[] dictionariesToCheck) { if (TextUtils.isEmpty(word)) { return false; } @@ -798,15 +725,13 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { if (dictionaryGroup.mLocale == null) { continue; } - final String lowerCasedWord = word.toLowerCase(dictionaryGroup.mLocale); - for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) { + for (final String dictType : dictionariesToCheck) { final Dictionary dictionary = dictionaryGroup.getDict(dictType); // Ideally the passed map would come out of a {@link java.util.concurrent.Future} and // would be immutable once it's finished initializing, but concretely a null test is // probably good enough for the time being. if (null == dictionary) continue; - if (dictionary.isValidWord(word) - || (ignoreCase && dictionary.isValidWord(lowerCasedWord))) { + if (dictionary.isValidWord(word)) { return true; } } @@ -822,7 +747,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { int maxFreq = Dictionary.NOT_A_PROBABILITY; final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : DICT_TYPES_ORDERED_TO_GET_SUGGESTIONS) { + for (final String dictType : ALL_DICTIONARY_TYPES) { final Dictionary dictionary = dictionaryGroup.getDict(dictType); if (dictionary == null) continue; final int tempFreq; @@ -861,64 +786,6 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { clearSubDictionary(Dictionary.TYPE_USER_HISTORY); } - // This method gets called only when the IME receives a notification to remove the - // personalization dictionary. - public void clearPersonalizationDictionary() { - clearSubDictionary(Dictionary.TYPE_PERSONALIZATION); - mPersonalizationHelper.clearDictionariesToUpdate(); - } - - public void clearContextualDictionary() { - clearSubDictionary(Dictionary.TYPE_CONTEXTUAL); - } - - public void addEntriesToPersonalizationDictionary( - final PersonalizationDataChunk personalizationDataChunk, - final SpacingAndPunctuations spacingAndPunctuations, - final UpdateEntriesForInputEventsCallback callback) { - mPersonalizationHelper.updateEntriesOfPersonalizationDictionaries( - getMostProbableLocale(), personalizationDataChunk, spacingAndPunctuations, - callback); - } - - @UsedForTesting - public void addPhraseToContextualDictionary(final String[] phrase, final int probability, - final int bigramProbabilityForWords, final int bigramProbabilityForPhrases) { - // TODO: we're inserting the phrase into the dictionary for the active language. Rethink - // this a bit from a theoretical point of view. - final ExpandableBinaryDictionary contextualDict = - getDictionaryGroupForMostProbableLanguage().getSubDict(Dictionary.TYPE_CONTEXTUAL); - if (contextualDict == null) { - return; - } - NgramContext ngramContext = NgramContext.BEGINNING_OF_SENTENCE; - for (int i = 0; i < phrase.length; i++) { - final String[] subPhrase = Arrays.copyOfRange(phrase, i /* start */, phrase.length); - final String subPhraseStr = TextUtils.join(Constants.WORD_SEPARATOR, subPhrase); - contextualDict.addUnigramEntryWithCheckingDistracter( - subPhraseStr, probability, null /* shortcutTarget */, - Dictionary.NOT_A_PROBABILITY /* shortcutFreq */, - false /* isNotAWord */, false /* isPossiblyOffensive */, - BinaryDictionary.NOT_A_VALID_TIMESTAMP, - DistracterFilter.EMPTY_DISTRACTER_FILTER); - contextualDict.addNgramEntry(ngramContext, subPhraseStr, - bigramProbabilityForPhrases, BinaryDictionary.NOT_A_VALID_TIMESTAMP); - - if (i < phrase.length - 1) { - contextualDict.addUnigramEntryWithCheckingDistracter( - phrase[i], probability, null /* shortcutTarget */, - Dictionary.NOT_A_PROBABILITY /* shortcutFreq */, - false /* isNotAWord */, false /* isPossiblyOffensive */, - BinaryDictionary.NOT_A_VALID_TIMESTAMP, - DistracterFilter.EMPTY_DISTRACTER_FILTER); - contextualDict.addNgramEntry(ngramContext, phrase[i], - bigramProbabilityForWords, BinaryDictionary.NOT_A_VALID_TIMESTAMP); - } - ngramContext = - ngramContext.getNextNgramContext(new NgramContext.WordInfo(phrase[i])); - } - } - public void dumpDictionaryForDebug(final String dictName) { final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { @@ -936,7 +803,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator { final ArrayList<Pair<String, DictionaryStats>> statsOfEnabledSubDicts = new ArrayList<>(); final DictionaryGroup[] dictionaryGroups = mDictionaryGroups; for (final DictionaryGroup dictionaryGroup : dictionaryGroups) { - for (final String dictType : SUB_DICT_TYPES) { + for (final String dictType : DYNAMIC_DICTIONARY_TYPES) { final ExpandableBinaryDictionary dictionary = dictionaryGroup.getSubDict(dictType); if (dictionary == null) continue; statsOfEnabledSubDicts.add(new Pair<>(dictType, dictionary.getDictionaryStats())); diff --git a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java index 13bd15101..85ecf93f3 100644 --- a/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java +++ b/java/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCache.java @@ -28,10 +28,11 @@ import android.util.LruCache; /** * Cache for dictionary facilitators of multiple locales. - * This class automatically creates and releases facilitator instances using LRU policy. + * This class automatically creates and releases up to 3 facilitator instances using LRU policy. */ public class DictionaryFacilitatorLruCache { - static final String TAG = DictionaryFacilitatorLruCache.class.getSimpleName(); + private static final String TAG = "DictionaryFacilitatorLruCache"; + private static final int MAX_DICTIONARY_FACILITATOR_COUNT = 3; private static final int WAIT_FOR_LOADING_MAIN_DICT_IN_MILLISECONDS = 1000; private static final int MAX_RETRY_COUNT_FOR_WAITING_FOR_LOADING_DICT = 5; @@ -74,10 +75,10 @@ public class DictionaryFacilitatorLruCache { private final Object mLock = new Object(); private boolean mUseContactsDictionary = false; - public DictionaryFacilitatorLruCache(final Context context, final int maxSize, - final String dictionaryNamePrefix) { + public DictionaryFacilitatorLruCache(final Context context, final String dictionaryNamePrefix) { mContext = context; - mLruCache = new DictionaryFacilitatorLruCacheInner(mCachedLocales, maxSize); + mLruCache = new DictionaryFacilitatorLruCacheInner( + mCachedLocales, MAX_DICTIONARY_FACILITATOR_COUNT); mDictionaryNamePrefix = dictionaryNamePrefix; } @@ -103,11 +104,10 @@ public class DictionaryFacilitatorLruCache { private void resetDictionariesForLocaleLocked(final DictionaryFacilitator dictionaryFacilitator, final Locale locale) { // Note: Given that personalized dictionaries are not used here; we can pass null account. - dictionaryFacilitator.resetDictionariesWithDictNamePrefix(mContext, new Locale[] { locale }, + dictionaryFacilitator.resetDictionaries(mContext, new Locale[]{locale}, mUseContactsDictionary, false /* usePersonalizedDicts */, - false /* forceReloadMainDictionary */, null /* listener */, - mDictionaryNamePrefix, - null /* account */); + false /* forceReloadMainDictionary */, null /* account */, + mDictionaryNamePrefix, null /* listener */); } public void setUseContactsDictionary(final boolean useContectsDictionary) { @@ -128,7 +128,7 @@ public class DictionaryFacilitatorLruCache { public DictionaryFacilitator get(final Locale locale) { DictionaryFacilitator dictionaryFacilitator = mLruCache.get(locale); if (dictionaryFacilitator != null) { - // dictionary falicitator for the locale is in the cache. + // dictionary facilitator for the locale is in the cache. return dictionaryFacilitator; } synchronized (mLock) { diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index 1c54a20e7..87d46e226 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -22,8 +22,8 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.ComposedData; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.FileUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; @@ -73,7 +73,8 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { /** * The maximum length of a word in this dictionary. */ - protected static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; + protected static final int MAX_WORD_LENGTH = + DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; private static final int DICTIONARY_FORMAT_VERSION = FormatSpec.VERSION4; diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java index 9fcdb2229..426d33e6d 100644 --- a/java/src/com/android/inputmethod/latin/LastComposedWord.java +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -19,8 +19,8 @@ package com.android.inputmethod.latin; import android.text.TextUtils; import com.android.inputmethod.event.Event; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.InputPointers; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import java.util.ArrayList; @@ -53,7 +53,7 @@ public final class LastComposedWord { public final NgramContext mNgramContext; public final int mCapitalizedMode; public final InputPointers mInputPointers = - new InputPointers(Constants.DICTIONARY_MAX_WORD_LENGTH); + new InputPointers(DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH); private boolean mActive; diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 622cdb0a6..74ef6481a 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -20,7 +20,6 @@ import static com.android.inputmethod.latin.common.Constants.ImeOption.FORCE_ASC import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE; import static com.android.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT; -import android.annotation.TargetApi; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -32,13 +31,11 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.inputmethodservice.InputMethodService; import android.media.AudioManager; -import android.os.Build; import android.os.Debug; import android.os.IBinder; import android.os.Message; import android.preference.PreferenceManager; import android.text.InputType; -import android.text.TextUtils; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Printer; @@ -47,18 +44,14 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup.LayoutParams; -import android.view.ViewTreeObserver; import android.view.Window; import android.view.WindowManager; import android.view.inputmethod.CompletionInfo; -import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodSubtype; -import android.widget.TextView; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater; @@ -72,7 +65,6 @@ import com.android.inputmethod.keyboard.KeyboardActionListener; import com.android.inputmethod.keyboard.KeyboardId; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.MainKeyboardView; -import com.android.inputmethod.keyboard.TextDecoratorUi; import com.android.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; @@ -81,9 +73,7 @@ import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.define.DebugFlags; import com.android.inputmethod.latin.define.ProductionFlags; import com.android.inputmethod.latin.inputlogic.InputLogic; -import com.android.inputmethod.latin.personalization.ContextualDictionaryUpdater; import com.android.inputmethod.latin.personalization.DictionaryDecayBroadcastReciever; -import com.android.inputmethod.latin.personalization.PersonalizationDictionaryUpdater; import com.android.inputmethod.latin.personalization.PersonalizationHelper; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsActivity; @@ -92,8 +82,6 @@ import com.android.inputmethod.latin.suggestions.SuggestionStripView; import com.android.inputmethod.latin.suggestions.SuggestionStripViewAccessor; import com.android.inputmethod.latin.touchinputconsumer.GestureConsumer; import com.android.inputmethod.latin.utils.ApplicationUtils; -import com.android.inputmethod.latin.utils.CapsModeUtils; -import com.android.inputmethod.latin.utils.CursorAnchorInfoUtils; import com.android.inputmethod.latin.utils.DialogUtils; import com.android.inputmethod.latin.utils.ImportantNoticeUtils; import com.android.inputmethod.latin.utils.IntentUtils; @@ -139,19 +127,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final String SCHEME_PACKAGE = "package"; final Settings mSettings; - private final DictionaryFacilitator mDictionaryFacilitator = - DictionaryFacilitatorProvider.newDictionaryFacilitator(this /* context */); - // TODO: Move from LatinIME. - private final PersonalizationDictionaryUpdater mPersonalizationDictionaryUpdater = - new PersonalizationDictionaryUpdater(this /* context */, mDictionaryFacilitator); - private final ContextualDictionaryUpdater mContextualDictionaryUpdater = - new ContextualDictionaryUpdater(this /* context */, mDictionaryFacilitator, - new Runnable() { - @Override - public void run() { - mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE); - } - }); + private final DictionaryFacilitator mDictionaryFacilitator = + DictionaryFacilitatorProvider.newDictionaryFacilitator(this /* context */); final InputLogic mInputLogic = new InputLogic(this /* LatinIME */, this /* SuggestionStripViewAccessor */, mDictionaryFacilitator); // We expect to have only one decoder in almost all cases, hence the default capacity of 1. @@ -162,7 +139,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private View mInputView; private InsetsUpdater mInsetsUpdater; private SuggestionStripView mSuggestionStripView; - private TextView mExtractEditText; private RichInputMethodManager mRichImm; @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; @@ -642,11 +618,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private void refreshPersonalizationDictionarySession( final SettingsValues currentSettingsValues) { + // TODO: Remove all existing personalized dictionaries. mDictionaryFacilitator.setIsMonolingualUser( mRichImm.isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes()); - mPersonalizationDictionaryUpdater.onLoadSettings( - currentSettingsValues.mUsePersonalizedDicts); - mContextualDictionaryUpdater.onLoadSettings(currentSettingsValues.mUsePersonalizedDicts); final boolean shouldKeepUserHistoryDictionaries; if (currentSettingsValues.mUsePersonalizedDicts) { shouldKeepUserHistoryDictionaries = true; @@ -705,7 +679,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mDictionaryFacilitator.resetDictionaries(this /* context */, locales, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, false /* forceReloadMainDictionary */, - settingsValues.mAccount, + settingsValues.mAccount, "" /* dictNamePrefix */, this /* DictionaryInitializationListener */); if (settingsValues.mAutoCorrectionEnabledPerUserSettings) { mInputLogic.mSuggest.setAutoCorrectionThreshold( @@ -723,15 +697,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mDictionaryFacilitator.getLocales(), settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, true /* forceReloadMainDictionary */, - settingsValues.mAccount, + settingsValues.mAccount, "" /* dictNamePrefix */, this /* DictionaryInitializationListener */); } @Override public void onDestroy() { mDictionaryFacilitator.closeDictionaries(); - mPersonalizationDictionaryUpdater.onDestroy(); - mContextualDictionaryUpdater.onDestroy(); mSettings.onDestroy(); NetworkConnectivityUtils.onDestroy(this /* context */); unregisterReceiver(mRingerModeChangeReceiver); @@ -793,57 +765,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (hasSuggestionStripView()) { mSuggestionStripView.setListener(this, view); } - mInputLogic.setTextDecoratorUi(new TextDecoratorUi(this, view)); } @Override - public void setExtractView(final View view) { - final TextView prevExtractEditText = mExtractEditText; - super.setExtractView(view); - TextView nextExtractEditText = null; - if (view != null) { - final View extractEditText = view.findViewById(android.R.id.inputExtractEditText); - if (extractEditText instanceof TextView) { - nextExtractEditText = (TextView)extractEditText; - } - } - if (prevExtractEditText == nextExtractEditText) { - return; - } - if (prevExtractEditText != null) { - prevExtractEditText.getViewTreeObserver().removeOnPreDrawListener( - mExtractTextViewPreDrawListener); - } - mExtractEditText = nextExtractEditText; - if (mExtractEditText != null) { - mExtractEditText.getViewTreeObserver().addOnPreDrawListener( - mExtractTextViewPreDrawListener); - } - } - - void updateCursorAnchorInfo() { - // CursorAnchorInfo is used on L and later. - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - if (isFullscreenMode() && mExtractEditText != null) { - mInputLogic.onUpdateCursorAnchorInfo( - CursorAnchorInfoUtils.extractFromTextView(mExtractEditText)); - } - } - } - - private final ViewTreeObserver.OnPreDrawListener mExtractTextViewPreDrawListener = - new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - updateCursorAnchorInfo(); - return true; - } - }; - - @Override public void setCandidatesView(final View view) { // To ensure that CandidatesView will never be set. - return; } @Override @@ -1050,8 +976,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen currentSettingsValues.mGestureTrailEnabled, currentSettingsValues.mGestureFloatingPreviewTextEnabled); - // Contextual dictionary should be updated for the current application. - mContextualDictionaryUpdater.onStartInputView(editorInfo.packageName); if (TRACE) Debug.startMethodTracing("/data/trace/latinime"); } @@ -1114,15 +1038,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) { - if (isFullscreenMode()) { - return; - } - mInputLogic.onUpdateCursorAnchorInfo(CursorAnchorInfoCompatWrapper.wrap(info)); - } - /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides @@ -1303,7 +1218,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void updateFullscreenMode() { super.updateFullscreenMode(); - mInputLogic.onUpdateFullscreenMode(isFullscreenMode()); updateSoftInputWindowLayoutParameters(); } @@ -1351,18 +1265,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return keyboard.getCoordinates(codePoints); } - // Callback for the {@link SuggestionStripView}, to call when the "add to dictionary" hint is - // pressed. - @Override - public void addWordToUserDictionary(final String word) { - if (TextUtils.isEmpty(word)) { - // Probably never supposed to happen, but just in case. - return; - } - mDictionaryFacilitator.addWordToUserDictionary(this /* context */, word); - mInputLogic.onAddWordToUserDictionary(); - } - // Callback for the {@link SuggestionStripView}, to call when the important notice strip is // pressed. @Override @@ -1557,19 +1459,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return null != mSuggestionStripView; } - @Override - public boolean isShowingAddToDictionaryHint() { - return hasSuggestionStripView() && mSuggestionStripView.isShowingAddToDictionaryHint(); - } - - @Override - public void dismissAddToDictionaryHint() { - if (!hasSuggestionStripView()) { - return; - } - mSuggestionStripView.dismissAddToDictionaryHint(); - } - private void setSuggestedWords(final SuggestedWords suggestedWords) { final SettingsValues currentSettingsValues = mSettings.getCurrent(); mInputLogic.setSuggestedWords(suggestedWords); @@ -1631,7 +1520,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return; } mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard.getProximityInfo(), - mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback); + mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback, + keyboard.getKeyboardLayout()); } @Override @@ -1658,21 +1548,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen updateStateAfterInputTransaction(completeInputTransaction); } - @Override - public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip) { - if (!hasSuggestionStripView()) { - return; - } - final String wordToShow; - if (CapsModeUtils.isAutoCapsMode(mInputLogic.mLastComposedWord.mCapitalizedMode)) { - wordToShow = word.toLowerCase(mDictionaryFacilitator.getMostProbableLocale()); - } else { - wordToShow = word; - } - mSuggestionStripView.showAddToDictionaryHint(wordToShow, - isFromSuggestionStrip /* shouldShowWordToSave */); - } - // This will show either an empty suggestion strip (if prediction is enabled) or // punctuation suggestions (if it's disabled). @Override @@ -1935,7 +1810,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mDictionaryFacilitator.resetDictionaries(this, new Locale[] { locale }, settingsValues.mUseContactsDict, settingsValues.mUsePersonalizedDicts, false /* forceReloadMainDictionary */, - settingsValues.mAccount, + settingsValues.mAccount, "", /* dictionaryNamePrefix */ this /* DictionaryInitializationListener */); } @@ -1943,7 +1818,6 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @UsedForTesting /* package for test */ void clearPersonalizedDictionariesForTest() { mDictionaryFacilitator.clearUserHistoryDictionary(); - mDictionaryFacilitator.clearPersonalizationDictionary(); } @UsedForTesting diff --git a/java/src/com/android/inputmethod/latin/NgramContext.java b/java/src/com/android/inputmethod/latin/NgramContext.java index b47731229..86155e0be 100644 --- a/java/src/com/android/inputmethod/latin/NgramContext.java +++ b/java/src/com/android/inputmethod/latin/NgramContext.java @@ -19,9 +19,10 @@ package com.android.inputmethod.latin; import android.text.TextUtils; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; +import java.util.ArrayList; import java.util.Arrays; import javax.annotation.Nonnull; @@ -38,6 +39,10 @@ public class NgramContext { public static final NgramContext BEGINNING_OF_SENTENCE = new NgramContext(WordInfo.BEGINNING_OF_SENTENCE_WORD_INFO); + public static final String BEGINNING_OF_SENTENCE_TAG = "<S>"; + + public static final String CONTEXT_SEPARATOR = " "; + /** * Word information used to represent previous words information. */ @@ -106,14 +111,39 @@ public class NgramContext { // Create next prevWordsInfo using current prevWordsInfo. @Nonnull public NgramContext getNextNgramContext(final WordInfo wordInfo) { - final int nextPrevWordCount = Math.min(Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM, - mPrevWordsCount + 1); + final int nextPrevWordCount = Math.min( + DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM, mPrevWordsCount + 1); final WordInfo[] prevWordsInfo = new WordInfo[nextPrevWordCount]; prevWordsInfo[0] = wordInfo; System.arraycopy(mPrevWordsInfo, 0, prevWordsInfo, 1, nextPrevWordCount - 1); return new NgramContext(prevWordsInfo); } + + /** + * Extracts the previous words context. + * + * @return a String with the previous words separated by white space. + */ + public String extractPrevWordsContext() { + final ArrayList<String> terms = new ArrayList<>(); + for (int i = mPrevWordsInfo.length - 1; i >= 0; --i) { + if (mPrevWordsInfo[i] != null && mPrevWordsInfo[i].isValid()) { + final NgramContext.WordInfo wordInfo = mPrevWordsInfo[i]; + if (wordInfo.mIsBeginningOfSentence) { + terms.add(BEGINNING_OF_SENTENCE_TAG); + } else { + final String term = wordInfo.mWord.toString(); + if (!term.isEmpty()) { + terms.add(term); + } + } + } + } + return terms.size() == 0 ? BEGINNING_OF_SENTENCE_TAG + : TextUtils.join(CONTEXT_SEPARATOR, terms); + } + public boolean isValid() { return mPrevWordsCount > 0 && mPrevWordsInfo[0].isValid(); } diff --git a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java b/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java deleted file mode 100644 index 8926c06b1..000000000 --- a/java/src/com/android/inputmethod/latin/PersonalizationHelperForDictionaryFacilitator.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2014 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 java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Locale; -import java.util.concurrent.atomic.AtomicInteger; - -import android.content.Context; -import android.view.inputmethod.InputMethodSubtype; - -import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback; -import com.android.inputmethod.latin.personalization.PersonalizationDataChunk; -import com.android.inputmethod.latin.personalization.PersonalizationDictionary; -import com.android.inputmethod.latin.settings.SpacingAndPunctuations; -import com.android.inputmethod.latin.utils.DistracterFilter; -import com.android.inputmethod.latin.utils.DistracterFilterCheckingIsInDictionary; -import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; -import com.android.inputmethod.latin.utils.WordInputEventForPersonalization; - -/** - * Class for managing and updating personalization dictionaries. - */ -public class PersonalizationHelperForDictionaryFacilitator { - private final Context mContext; - private final DistracterFilter mDistracterFilter; - private final HashMap<String, HashSet<Locale>> mLangToLocalesMap = new HashMap<>(); - private final HashMap<Locale, ExpandableBinaryDictionary> mPersonalizationDictsToUpdate = - new HashMap<>(); - private boolean mIsMonolingualUser = false; - - PersonalizationHelperForDictionaryFacilitator(final Context context, - final DistracterFilter distracterFilter) { - mContext = context; - mDistracterFilter = distracterFilter; - } - - public void close() { - mLangToLocalesMap.clear(); - for (final ExpandableBinaryDictionary dict : mPersonalizationDictsToUpdate.values()) { - dict.close(); - } - mPersonalizationDictsToUpdate.clear(); - } - - public void clearDictionariesToUpdate() { - for (final ExpandableBinaryDictionary dict : mPersonalizationDictsToUpdate.values()) { - dict.clear(); - } - mPersonalizationDictsToUpdate.clear(); - } - - public void updateEnabledSubtypes(final List<InputMethodSubtype> enabledSubtypes) { - for (final InputMethodSubtype subtype : enabledSubtypes) { - final Locale locale = SubtypeLocaleUtils.getSubtypeLocale(subtype); - final String language = locale.getLanguage(); - final HashSet<Locale> locales = mLangToLocalesMap.get(language); - if (locales != null) { - locales.add(locale); - } else { - final HashSet<Locale> localeSet = new HashSet<>(); - localeSet.add(locale); - mLangToLocalesMap.put(language, localeSet); - } - } - } - - public void setIsMonolingualUser(final boolean isMonolingualUser) { - mIsMonolingualUser = isMonolingualUser; - } - - /** - * Flush personalization dictionaries to dictionary files. Close dictionaries after writing - * files except the dictionaries that is used for generating suggestions. - * - * @param personalizationDictsUsedForSuggestion the personalization dictionaries used for - * generating suggestions that won't be closed. - */ - public void flushPersonalizationDictionariesToUpdate( - final HashSet<ExpandableBinaryDictionary> personalizationDictsUsedForSuggestion) { - for (final ExpandableBinaryDictionary personalizationDict : - mPersonalizationDictsToUpdate.values()) { - personalizationDict.asyncFlushBinaryDictionary(); - if (!personalizationDictsUsedForSuggestion.contains(personalizationDict)) { - // Close if the dictionary is not being used for suggestion. - personalizationDict.close(); - } - } - mDistracterFilter.close(); - mPersonalizationDictsToUpdate.clear(); - } - - private ExpandableBinaryDictionary getPersonalizationDictToUpdate(final Context context, - final Locale locale) { - ExpandableBinaryDictionary personalizationDict = mPersonalizationDictsToUpdate.get(locale); - if (personalizationDict != null) { - return personalizationDict; - } - personalizationDict = PersonalizationDictionary.getDictionary(context, locale, - null /* dictFile */, "" /* dictNamePrefix */, null /* account */); - mPersonalizationDictsToUpdate.put(locale, personalizationDict); - return personalizationDict; - } - - private void updateEntriesOfPersonalizationDictionariesForLocale(final Locale locale, - final PersonalizationDataChunk personalizationDataChunk, - final SpacingAndPunctuations spacingAndPunctuations, - final UpdateEntriesForInputEventsCallback callback) { - final ExpandableBinaryDictionary personalizationDict = - getPersonalizationDictToUpdate(mContext, locale); - if (personalizationDict == null) { - if (callback != null) { - callback.onFinished(); - } - return; - } - final ArrayList<WordInputEventForPersonalization> inputEvents = - WordInputEventForPersonalization.createInputEventFrom( - personalizationDataChunk.mTokens, - personalizationDataChunk.mTimestampInSeconds, spacingAndPunctuations, - locale, new DistracterFilterCheckingIsInDictionary( - mDistracterFilter, personalizationDict)); - if (inputEvents == null || inputEvents.isEmpty()) { - if (callback != null) { - callback.onFinished(); - } - return; - } - personalizationDict.updateEntriesForInputEvents(inputEvents, callback); - } - - public void updateEntriesOfPersonalizationDictionaries(final Locale defaultLocale, - final PersonalizationDataChunk personalizationDataChunk, - final SpacingAndPunctuations spacingAndPunctuations, - final UpdateEntriesForInputEventsCallback callback) { - final String language = personalizationDataChunk.mDetectedLanguage; - final HashSet<Locale> locales; - if (mIsMonolingualUser && PersonalizationDataChunk.LANGUAGE_UNKNOWN.equals(language) - && mLangToLocalesMap.size() == 1) { - locales = mLangToLocalesMap.get(defaultLocale.getLanguage()); - } else { - locales = mLangToLocalesMap.get(language); - } - if (locales == null || locales.isEmpty()) { - if (callback != null) { - callback.onFinished(); - } - return; - } - final AtomicInteger remainingTaskCount = new AtomicInteger(locales.size()); - final UpdateEntriesForInputEventsCallback callbackForLocales = - new UpdateEntriesForInputEventsCallback() { - @Override - public void onFinished() { - if (remainingTaskCount.decrementAndGet() == 0) { - // Update tasks for all locales have been finished. - if (callback != null) { - callback.onFinished(); - } - } - } - }; - for (final Locale locale : locales) { - updateEntriesOfPersonalizationDictionariesForLocale(locale, personalizationDataChunk, - spacingAndPunctuations, callbackForLocales); - } - } -} diff --git a/java/src/com/android/inputmethod/latin/RichInputConnection.java b/java/src/com/android/inputmethod/latin/RichInputConnection.java index 834f747d9..0210d7e18 100644 --- a/java/src/com/android/inputmethod/latin/RichInputConnection.java +++ b/java/src/com/android/inputmethod/latin/RichInputConnection.java @@ -16,14 +16,14 @@ package com.android.inputmethod.latin; -import android.graphics.Color; +import static com.android.inputmethod.latin.define.DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; + import android.inputmethodservice.InputMethodService; import android.os.Build; import android.os.Bundle; import android.text.SpannableStringBuilder; -import android.text.Spanned; import android.text.TextUtils; -import android.text.style.BackgroundColorSpan; +import android.text.style.CharacterStyle; import android.util.Log; import android.view.KeyEvent; import android.view.inputmethod.CompletionInfo; @@ -35,7 +35,9 @@ import android.view.inputmethod.InputMethodManager; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.common.UnicodeSurrogate; import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.inputlogic.PrivateCommandPerformer; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.CapsModeUtils; @@ -61,9 +63,9 @@ public final class RichInputConnection implements PrivateCommandPerformer { private static final boolean DEBUG_PREVIOUS_TEXT = false; private static final boolean DEBUG_BATCH_NESTING = false; // Provision for long words and separators between the words. - private static final int LOOKBACK_CHARACTER_NUM = Constants.DICTIONARY_MAX_WORD_LENGTH - * (Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1) /* words */ - + Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM /* separators */; + private static final int LOOKBACK_CHARACTER_NUM = DICTIONARY_MAX_WORD_LENGTH + * (DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM + 1) /* words */ + + DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM /* separators */; private static final int INVALID_CURSOR_POSITION = -1; /** @@ -91,16 +93,10 @@ public final class RichInputConnection implements PrivateCommandPerformer { private final StringBuilder mComposingText = new StringBuilder(); /** - * This variable is a temporary object used in - * {@link #commitTextWithBackgroundColor(CharSequence,int,int,int)} to avoid object creation. + * This variable is a temporary object used in {@link #commitText(CharSequence,int)} + * to avoid object creation. */ private SpannableStringBuilder mTempObjectForCommitText = new SpannableStringBuilder(); - /** - * This variable is used to track whether the last committed text had the background color or - * not. - * TODO: Omit this flag if possible. - */ - private boolean mLastCommittedTextHasBackgroundColor = false; private final InputMethodService mParent; InputConnection mIC; @@ -239,39 +235,18 @@ public final class RichInputConnection implements PrivateCommandPerformer { // it works, but it's wrong and should be fixed. mCommittedTextBeforeComposingText.append(mComposingText); mComposingText.setLength(0); - // TODO: Clear this flag in setComposingRegion() and setComposingText() as well if needed. - mLastCommittedTextHasBackgroundColor = false; if (null != mIC) { mIC.finishComposingText(); } } /** - * Synonym of {@code commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT}. + * Calls {@link InputConnection#commitText(CharSequence, int)}. + * * @param text The text to commit. This may include styles. - * See {@link InputConnection#commitText(CharSequence, int)}. * @param newCursorPosition The new cursor position around the text. - * See {@link InputConnection#commitText(CharSequence, int)}. */ public void commitText(final CharSequence text, final int newCursorPosition) { - commitTextWithBackgroundColor(text, newCursorPosition, Color.TRANSPARENT, text.length()); - } - - /** - * Calls {@link InputConnection#commitText(CharSequence, int)} with the given background color. - * @param text The text to commit. This may include styles. - * See {@link InputConnection#commitText(CharSequence, int)}. - * @param newCursorPosition The new cursor position around the text. - * See {@link InputConnection#commitText(CharSequence, int)}. - * @param color The background color to be attached. Set {@link Color#TRANSPARENT} to disable - * the background color. Note that this method specifies {@link BackgroundColorSpan} with - * {@link Spanned#SPAN_COMPOSING} flag, meaning that the background color persists until - * {@link #finishComposingText()} is called. - * @param coloredTextLength the length of text, in Java chars, which should be rendered with - * the given background color. - */ - public void commitTextWithBackgroundColor(final CharSequence text, final int newCursorPosition, - final int color, final int coloredTextLength) { if (DEBUG_BATCH_NESTING) checkBatchEdit(); if (DEBUG_PREVIOUS_TEXT) checkConsistencyForDebug(); mCommittedTextBeforeComposingText.append(text); @@ -281,44 +256,32 @@ public final class RichInputConnection implements PrivateCommandPerformer { mExpectedSelStart += text.length() - mComposingText.length(); mExpectedSelEnd = mExpectedSelStart; mComposingText.setLength(0); - mLastCommittedTextHasBackgroundColor = false; if (null != mIC) { - if (color == Color.TRANSPARENT) { - mIC.commitText(text, newCursorPosition); - } else { - mTempObjectForCommitText.clear(); - mTempObjectForCommitText.append(text); - final BackgroundColorSpan backgroundColorSpan = new BackgroundColorSpan(color); - final int spanLength = Math.min(coloredTextLength, text.length()); - mTempObjectForCommitText.setSpan(backgroundColorSpan, 0, spanLength, - Spanned.SPAN_COMPOSING | Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - mIC.commitText(mTempObjectForCommitText, newCursorPosition); - mLastCommittedTextHasBackgroundColor = true; + mTempObjectForCommitText.clear(); + mTempObjectForCommitText.append(text); + final CharacterStyle[] spans = mTempObjectForCommitText.getSpans( + 0, text.length(), CharacterStyle.class); + for (final CharacterStyle span : spans) { + final int spanStart = mTempObjectForCommitText.getSpanStart(span); + final int spanEnd = mTempObjectForCommitText.getSpanEnd(span); + final int spanFlags = mTempObjectForCommitText.getSpanFlags(span); + // We have to adjust the end of the span to include an additional character. + // This is to avoid splitting a unicode surrogate pair. + // See com.android.inputmethod.latin.common.Constants.UnicodeSurrogate + // See https://b.corp.google.com/issues/19255233 + if (0 < spanEnd && spanEnd < mTempObjectForCommitText.length()) { + final char spanEndChar = mTempObjectForCommitText.charAt(spanEnd - 1); + final char nextChar = mTempObjectForCommitText.charAt(spanEnd); + if (UnicodeSurrogate.isLowSurrogate(spanEndChar) + && UnicodeSurrogate.isHighSurrogate(nextChar)) { + mTempObjectForCommitText.setSpan(span, spanStart, spanEnd + 1, spanFlags); + } + } } + mIC.commitText(mTempObjectForCommitText, newCursorPosition); } } - /** - * Removes the background color from the highlighted text if necessary. Should be called while - * there is no on-going composing text. - * - * <p>CAVEAT: This method internally calls {@link InputConnection#finishComposingText()}. - * Be careful of any unexpected side effects.</p> - */ - public void removeBackgroundColorFromHighlightedTextIfNecessary() { - // TODO: We haven't yet full tested if we really need to check this flag or not. Omit this - // flag if everything works fine without this condition. - if (!mLastCommittedTextHasBackgroundColor) { - return; - } - if (mComposingText.length() > 0) { - Log.e(TAG, "clearSpansWithComposingFlags should be called when composing text is " + - "empty. mComposingText=" + mComposingText); - return; - } - finishComposingText(); - } - public CharSequence getSelectedText(final int flags) { return (null == mIC) ? null : mIC.getSelectedText(flags); } @@ -946,8 +909,6 @@ public final class RichInputConnection implements PrivateCommandPerformer { } } - private boolean mCursorAnchorInfoMonitorEnabled = false; - /** * Requests the editor to call back {@link InputMethodManager#updateCursorAnchorInfo}. * @param enableMonitor {@code true} to request the editor to call back the method whenever the @@ -962,23 +923,10 @@ public final class RichInputConnection implements PrivateCommandPerformer { public boolean requestCursorUpdates(final boolean enableMonitor, final boolean requestImmediateCallback) { mIC = mParent.getCurrentInputConnection(); - final boolean scheduled; - if (null != mIC) { - scheduled = InputConnectionCompatUtils.requestCursorUpdates(mIC, enableMonitor, - requestImmediateCallback); - } else { - scheduled = false; + if (mIC == null) { + return false; } - mCursorAnchorInfoMonitorEnabled = (scheduled && enableMonitor); - return scheduled; - } - - /** - * @return {@code true} if the application reported that the monitor mode of - * {@link InputMethodService#onUpdateCursorAnchorInfo(android.view.inputmethod.CursorAnchorInfo)} - * is currently enabled. - */ - public boolean isCursorAnchorInfoMonitorEnabled() { - return mCursorAnchorInfoMonitorEnabled; + return InputConnectionCompatUtils.requestCursorUpdates( + mIC, enableMonitor, requestImmediateCallback); } } diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 0bf0f687a..ddb2b5358 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -18,6 +18,7 @@ package com.android.inputmethod.latin; import android.text.TextUtils; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.common.Constants; @@ -97,14 +98,16 @@ public final class Suggest { final NgramContext ngramContext, final ProximityInfo proximityInfo, final SettingsValuesForSuggestion settingsValuesForSuggestion, final boolean isCorrectionEnabled, final int inputStyle, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) { + final OnGetSuggestedWordsCallback callback, + final KeyboardLayout keyboardLayout) { if (wordComposer.isBatchMode()) { getSuggestedWordsForBatchInput(wordComposer, ngramContext, proximityInfo, - settingsValuesForSuggestion, inputStyle, sequenceNumber, callback); + settingsValuesForSuggestion, inputStyle, sequenceNumber, callback, + keyboardLayout); } else { getSuggestedWordsForNonBatchInput(wordComposer, ngramContext, proximityInfo, settingsValuesForSuggestion, inputStyle, isCorrectionEnabled, - sequenceNumber, callback); + sequenceNumber, callback, keyboardLayout); } } @@ -163,7 +166,8 @@ public final class Suggest { final NgramContext ngramContext, final ProximityInfo proximityInfo, final SettingsValuesForSuggestion settingsValuesForSuggestion, final int inputStyleIfNotPrediction, final boolean isCorrectionEnabled, - final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { + final int sequenceNumber, final OnGetSuggestedWordsCallback callback, + final KeyboardLayout keyboardLayout) { final String typedWordString = wordComposer.getTypedWord(); final int trailingSingleQuotesCount = StringUtils.getTrailingSingleQuotesCount(typedWordString); @@ -173,7 +177,8 @@ public final class Suggest { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(), - settingsValuesForSuggestion, SESSION_ID_TYPING); + settingsValuesForSuggestion, SESSION_ID_TYPING, inputStyleIfNotPrediction, + keyboardLayout); final Locale mostProbableLocale = mDictionaryFacilitator.getMostProbableLocale(); final ArrayList<SuggestedWordInfo> suggestionsContainer = getTransformedSuggestedWordInfoList(wordComposer, suggestionResults, @@ -270,7 +275,9 @@ public final class Suggest { hasAutoCorrection = false; } else { final SuggestedWordInfo firstSuggestion = suggestionResults.first(); - if (!AutoCorrectionUtils.suggestionExceedsThreshold( + if (suggestionResults.mAutocorrectRecommendation) { + hasAutoCorrection = true; + } else if (!AutoCorrectionUtils.suggestionExceedsThreshold( firstSuggestion, consideredWord, mAutoCorrectionThreshold)) { // Score is too low for autocorrect hasAutoCorrection = false; @@ -339,10 +346,11 @@ public final class Suggest { final NgramContext ngramContext, final ProximityInfo proximityInfo, final SettingsValuesForSuggestion settingsValuesForSuggestion, final int inputStyle, final int sequenceNumber, - final OnGetSuggestedWordsCallback callback) { + final OnGetSuggestedWordsCallback callback, + final KeyboardLayout keyboardLayout) { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, ngramContext, proximityInfo.getNativeProximityInfo(), - settingsValuesForSuggestion, SESSION_ID_GESTURE); + settingsValuesForSuggestion, SESSION_ID_GESTURE, inputStyle, keyboardLayout); // For transforming words that don't come from a dictionary, because it's our best bet final Locale defaultLocale = mDictionaryFacilitator.getMostProbableLocale(); final ArrayList<SuggestedWordInfo> suggestionsContainer = diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index df8db0cd2..913b63a61 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -112,6 +112,14 @@ public class SuggestedWords { } /** + * Get {@link SuggestedWordInfo} object for the typed word. + * @return The {@link SuggestedWordInfo} object for the typed word. + */ + public SuggestedWordInfo getTypedWordInfo() { + return mTypedWordInfo; + } + + /** * Get suggested word at <code>index</code>. * @param index The index of the suggested word. * @return The suggested word. @@ -347,6 +355,14 @@ public class SuggestedWords { return mDebugString; } + public String getWord() { + return mWord; + } + + public Dictionary getSourceDictionary() { + return mSourceDict; + } + public int codePointAt(int i) { return mWord.codePointAt(i); } diff --git a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java index 2d2b3d0a6..1ed210377 100644 --- a/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/UserBinaryDictionary.java @@ -16,7 +16,6 @@ package com.android.inputmethod.latin; -import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; @@ -29,7 +28,6 @@ import android.text.TextUtils; import android.util.Log; import com.android.inputmethod.annotations.ExternallyReferenced; -import com.android.inputmethod.compat.UserDictionaryCompatUtils; import com.android.inputmethod.latin.utils.SubtypeLocaleUtils; import java.io.File; @@ -54,13 +52,13 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { private static final int USER_DICT_SHORTCUT_FREQUENCY = 14; private static final String[] PROJECTION_QUERY_WITH_SHORTCUT = new String[] { - Words.WORD, - Words.SHORTCUT, - Words.FREQUENCY, + Words.WORD, + Words.SHORTCUT, + Words.FREQUENCY, }; private static final String[] PROJECTION_QUERY_WITHOUT_SHORTCUT = new String[] { - Words.WORD, - Words.FREQUENCY, + Words.WORD, + Words.FREQUENCY, }; private static final String NAME = "userunigram"; @@ -70,7 +68,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { final private boolean mAlsoUseMoreRestrictiveLocales; protected UserBinaryDictionary(final Context context, final Locale locale, - final boolean alsoUseMoreRestrictiveLocales, final File dictFile, final String name) { + final boolean alsoUseMoreRestrictiveLocales, + final File dictFile, final String name) { super(context, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_USER, dictFile); if (null == locale) throw new NullPointerException(); // Catch the error earlier final String localeStr = locale.toString(); @@ -105,9 +104,11 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. @ExternallyReferenced - public static UserBinaryDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix, @Nullable final String account) { - return new UserBinaryDictionary(context, locale, false /* alsoUseMoreRestrictiveLocales */, + public static UserBinaryDictionary getDictionary( + final Context context, final Locale locale, final File dictFile, + final String dictNamePrefix, @Nullable final String account) { + return new UserBinaryDictionary( + context, locale, false /* alsoUseMoreRestrictiveLocales */, dictFile, dictNamePrefix + NAME); } @@ -187,7 +188,8 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } private void addWordsFromProjectionLocked(final String[] query, String request, - final String[] requestArguments) throws IllegalArgumentException { + final String[] requestArguments) + throws IllegalArgumentException { Cursor cursor = null; try { cursor = mContext.getContentResolver().query( @@ -204,31 +206,6 @@ public class UserBinaryDictionary extends ExpandableBinaryDictionary { } } - public static boolean isEnabled(final Context context) { - final ContentResolver cr = context.getContentResolver(); - final ContentProviderClient client = cr.acquireContentProviderClient(Words.CONTENT_URI); - if (client != null) { - client.release(); - return true; - } - return false; - } - - /** - * Adds a word to the user dictionary and makes it persistent. - * - * @param context the context - * @param locale the locale - * @param word the word to add. If the word is capitalized, then the dictionary will - * recognize it as a capitalized word when searched. - */ - public static void addWordToUserDictionary(final Context context, final Locale locale, - final String word) { - // Update the user dictionary provider - UserDictionaryCompatUtils.addWord(context, word, - HISTORICAL_DEFAULT_USER_DICTIONARY_FREQUENCY, null, locale); - } - private static int scaleFrequencyFromDefaultToLatinIme(final int defaultFrequency) { // The default frequency for the user dictionary is 250 for historical reasons. // Latin IME considers a good value for the default user dictionary frequency diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index e80e3628f..32ef1021d 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -16,6 +16,7 @@ package com.android.inputmethod.latin; +import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.event.CombinerChain; import com.android.inputmethod.event.Event; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; @@ -25,6 +26,7 @@ import com.android.inputmethod.latin.common.CoordinateUtils; import com.android.inputmethod.latin.common.InputPointers; import com.android.inputmethod.latin.common.StringUtils; import com.android.inputmethod.latin.define.DebugFlags; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import java.util.ArrayList; import java.util.Collections; @@ -35,7 +37,7 @@ import javax.annotation.Nonnull; * A place to store the currently composing word with information such as adjacent key codes as well */ public final class WordComposer { - private static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; + private static final int MAX_WORD_LENGTH = DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; private static final boolean DBG = DebugFlags.DEBUG_ENABLED; public static final int CAPS_MODE_OFF = 0; @@ -464,4 +466,14 @@ public final class WordComposer { public String getRejectedBatchModeSuggestion() { return mRejectedBatchModeSuggestion; } + + @UsedForTesting + void addInputPointerForTest(int index, int keyX, int keyY) { + mInputPointers.addPointerAt(index, keyX, keyY, 0, 0); + } + + @UsedForTesting + void setTypedWordCacheForTests(String typedWordCacheForTests) { + mTypedWordCache = typedWordCacheForTests; + } } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 4842438c8..9154cc35a 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -17,7 +17,6 @@ package com.android.inputmethod.latin.inputlogic; import android.graphics.Color; -import android.inputmethodservice.InputMethodService; import android.os.SystemClock; import android.text.SpannableString; import android.text.Spanned; @@ -28,17 +27,14 @@ import android.util.Log; import android.view.KeyCharacterMap; import android.view.KeyEvent; import android.view.inputmethod.CorrectionInfo; -import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; -import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import com.android.inputmethod.compat.SuggestionSpanUtils; import com.android.inputmethod.event.Event; import com.android.inputmethod.event.InputTransaction; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.keyboard.KeyboardSwitcher; import com.android.inputmethod.keyboard.ProximityInfo; -import com.android.inputmethod.keyboard.TextDecorator; -import com.android.inputmethod.keyboard.TextDecoratorUiOperator; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.LastComposedWord; @@ -91,14 +87,6 @@ public final class InputLogic { public final Suggest mSuggest; private final DictionaryFacilitator mDictionaryFacilitator; - private final TextDecorator mTextDecorator = new TextDecorator(new TextDecorator.Listener() { - @Override - public void onClickComposingTextToAddToDictionary(final String word) { - mLatinIME.addWordToUserDictionary(word); - mLatinIME.dismissAddToDictionaryHint(); - } - }); - public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; // This has package visibility so it can be accessed from InputLogicHandler. /* package */ final WordComposer mWordComposer; @@ -174,7 +162,6 @@ public final class InputLogic { mConnection.requestCursorUpdates(true /* enableMonitor */, true /* requestImmediateCallback */); } - mTextDecorator.reset(); } /** @@ -269,20 +256,6 @@ public final class InputLogic { } /** - * Determines whether "Touch again to save" should be shown or not. - * @param suggestionInfo the suggested word chosen by the user. - * @return {@code true} if we should show the "Touch again to save" hint. - */ - private boolean shouldShowAddToDictionaryHint(final SuggestedWordInfo suggestionInfo) { - // We should show the "Touch again to save" hint if the user pressed the first entry - // AND it's in none of our current dictionaries (main, user or otherwise). - return (suggestionInfo.isKindOf(SuggestedWordInfo.KIND_TYPED) - || suggestionInfo.isKindOf(SuggestedWordInfo.KIND_OOV_CORRECTION)) - && !mDictionaryFacilitator.isValidWord(suggestionInfo.mWord, true /* ignoreCase */) - && mDictionaryFacilitator.isUserDictionaryEnabled(); - } - - /** * A suggestion was picked from the suggestion strip. * @param settingsValues the current values of the settings. * @param suggestionInfo the suggestion info. @@ -340,7 +313,6 @@ public final class InputLogic { return inputTransaction; } - final boolean shouldShowAddToDictionaryHint = shouldShowAddToDictionaryHint(suggestionInfo); commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); mConnection.endBatchEdit(); @@ -350,14 +322,9 @@ public final class InputLogic { mSpaceState = SpaceState.PHANTOM; inputTransaction.requireShiftUpdate(InputTransaction.SHIFT_UPDATE_NOW); - if (shouldShowAddToDictionaryHint) { - mSuggestionStripViewAccessor.suggestAddingToDictionary(suggestion, - true /* isFromSuggestionStrip */); - } else { - // If we're not showing the "Touch again to save", then update the suggestion strip. - // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE. - handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE); - } + // If we're not showing the "Touch again to save", then update the suggestion strip. + // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE. + handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE); StatsUtils.onPickSuggestionManually(mSuggestedWords, suggestionInfo); StatsUtils.onWordCommitSuggestionPickedManually( @@ -431,11 +398,6 @@ public final class InputLogic { // The cursor has been moved : we now accept to perform recapitalization mRecapitalizeStatus.enable(); - // We moved the cursor and need to invalidate the indicator right now. - mTextDecorator.reset(); - // Remaining background color that was used for the add-to-dictionary indicator should be - // removed. - mConnection.removeBackgroundColorFromHighlightedTextIfNecessary(); // We moved the cursor. If we are touching a word, we need to resume suggestion. mLatinIME.mHandler.postResumeSuggestions(true /* shouldDelay */); // Stop the last recapitalization, if started. @@ -513,9 +475,7 @@ public final class InputLogic { handler.cancelUpdateSuggestionStrip(); ++mAutoCommitSequenceNumber; mConnection.beginBatchEdit(); - if (!mWordComposer.isComposingWord()) { - mConnection.removeBackgroundColorFromHighlightedTextIfNecessary(); - } else { + if (mWordComposer.isComposingWord()) { if (mWordComposer.isCursorFrontOrMiddleOfComposingWord()) { // If we are in the middle of a recorrection, we need to commit the recorrection // first so that we can insert the batch input at the current cursor position. @@ -806,16 +766,6 @@ public final class InputLogic { final InputTransaction inputTransaction, // TODO: remove this argument final LatinIME.UIHandler handler) { - if (!mWordComposer.isComposingWord()) { - mConnection.removeBackgroundColorFromHighlightedTextIfNecessary(); - // In case the "add to dictionary" hint was still displayed. - // TODO: Do we really need to check if we have composing text here? - if (mSuggestionStripViewAccessor.isShowingAddToDictionaryHint()) { - mSuggestionStripViewAccessor.dismissAddToDictionaryHint(); - mTextDecorator.reset(); - } - } - final int codePoint = event.mCodePoint; mSpaceState = SpaceState.NONE; if (inputTransaction.mSettingsValues.isWordSeparator(codePoint) @@ -1639,20 +1589,8 @@ public final class InputLogic { 0 /* start */, lastCharIndex /* end */, 0 /* flags */); } - final boolean shouldShowAddToDictionaryForTypedWord = - shouldShowAddToDictionaryForTypedWord(mLastComposedWord, settingsValues); - if (inputTransaction.mSettingsValues.mSpacingAndPunctuations.mCurrentLanguageHasSpaces) { - // For languages with spaces, we revert to the typed string, but the cursor is still - // after the separator so we don't resume suggestions. If the user wants to correct - // the word, they have to press backspace again. - if (shouldShowAddToDictionaryForTypedWord) { - mConnection.commitTextWithBackgroundColor(textToCommit, 1, - settingsValues.mTextHighlightColorForAddToDictionaryIndicator, - originallyTypedWordString.length()); - } else { - mConnection.commitText(textToCommit, 1); - } + mConnection.commitText(textToCommit, 1); if (usePhantomSpace) { mSpaceState = SpaceState.PHANTOM; } @@ -1662,33 +1600,13 @@ public final class InputLogic { final int[] codePoints = StringUtils.toCodePointArray(stringToCommit); mWordComposer.setComposingWord(codePoints, mLatinIME.getCoordinatesForCurrentKeyboard(codePoints)); - if (shouldShowAddToDictionaryForTypedWord) { - setComposingTextInternalWithBackgroundColor(textToCommit, 1, - settingsValues.mTextHighlightColorForAddToDictionaryIndicator, - originallyTypedWordString.length()); - } else { - setComposingTextInternal(textToCommit, 1); - } + setComposingTextInternal(textToCommit, 1); } // Don't restart suggestion yet. We'll restart if the user deletes the separator. mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; - if (shouldShowAddToDictionaryForTypedWord) { - // Due to the API limitation as of L, we cannot reliably retrieve the reverted text - // when the separator causes line breaking. Until this API limitation is addressed in - // the framework, show the indicator only when the separator doesn't contain - // line-breaking characters. - if (!StringUtils.hasLineBreakCharacter(separatorString)) { - mTextDecorator.showAddToDictionaryIndicator(originallyTypedWordString, - mConnection.getExpectedSelectionStart(), - mConnection.getExpectedSelectionEnd()); - } - mSuggestionStripViewAccessor.suggestAddingToDictionary(originallyTypedWordString, - false /* isFromSuggestionStrip */); - } else { - // We have a separator between the word and the cursor: we should show predictions. - inputTransaction.setRequiresUpdateSuggestions(); - } + // We have a separator between the word and the cursor: we should show predictions. + inputTransaction.setRequiresUpdateSuggestions(); } /** @@ -2192,7 +2110,8 @@ public final class InputLogic { public void getSuggestedWords(final SettingsValues settingsValues, final ProximityInfo proximityInfo, final int keyboardShiftMode, final int inputStyle, - final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { + final int sequenceNumber, final OnGetSuggestedWordsCallback callback, + final KeyboardLayout keyboardLayout) { mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions( getActualCapsMode(settingsValues, keyboardShiftMode)); mSuggest.getSuggestedWords(mWordComposer, @@ -2206,7 +2125,7 @@ public final class InputLogic { new SettingsValuesForSuggestion(settingsValues.mBlockPotentiallyOffensive, settingsValues.mPhraseGestureEnabled), settingsValues.mAutoCorrectionEnabledPerUserSettings, - inputStyle, sequenceNumber, callback); + inputStyle, sequenceNumber, callback, keyboardLayout); } /** @@ -2215,7 +2134,7 @@ public final class InputLogic { * * <p>Currently using this method is optional and you can still directly call * {@link RichInputConnection#setComposingText(CharSequence, int)}, but it is recommended to - * use this method whenever possible to optimize the behavior of {@link TextDecorator}.<p> + * use this method whenever possible.<p> * <p>TODO: Should we move this mechanism to {@link RichInputConnection}?</p> * * @param newComposingText the composing text to be set @@ -2300,71 +2219,4 @@ public final class InputLogic { public int getComposingLength() { return mWordComposer.size(); } - - ////////////////////////////////////////////////////////////////////////////////////////////// - // Following methods are tentatively placed in this class for the integration with - // TextDecorator. - // TODO: Decouple things that are not related to the input logic. - ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Sets the UI operator for {@link TextDecorator}. - * @param uiOperator the UI operator which should be associated with {@link TextDecorator}. - */ - public void setTextDecoratorUi(@Nonnull final TextDecoratorUiOperator uiOperator) { - mTextDecorator.setUiOperator(uiOperator); - } - - /** - * Must be called from {@link InputMethodService#onUpdateCursorAnchorInfo(CursorAnchorInfo)} is - * called. - * @param info The wrapper object with which we can access cursor/anchor info. - */ - public void onUpdateCursorAnchorInfo(final CursorAnchorInfoCompatWrapper info) { - mTextDecorator.onUpdateCursorAnchorInfo(info); - } - - /** - * Must be called when {@link InputMethodService#updateFullscreenMode} is called. - * @param isFullscreen {@code true} if the input method is in full-screen mode. - */ - public void onUpdateFullscreenMode(final boolean isFullscreen) { - mTextDecorator.notifyFullScreenMode(isFullscreen); - } - - /** - * Must be called from {@link LatinIME#addWordToUserDictionary(String)}. - */ - public void onAddWordToUserDictionary() { - mConnection.removeBackgroundColorFromHighlightedTextIfNecessary(); - mTextDecorator.reset(); - } - - /** - * Returns whether the add to dictionary indicator should be shown or not. - * @param lastComposedWord the last composed word information. - * @param settingsValues the current settings value. - * @return {@code true} if the commit indicator should be shown. - */ - private boolean shouldShowAddToDictionaryForTypedWord(final LastComposedWord lastComposedWord, - final SettingsValues settingsValues) { - if (!mConnection.isCursorAnchorInfoMonitorEnabled()) { - // We cannot help in this case because we are heavily relying on this new API. - return false; - } - if (!settingsValues.mShouldShowLxxSuggestionUi) { - return false; - } - if (TextUtils.isEmpty(lastComposedWord.mTypedWord)) { - return false; - } - if (TextUtils.equals(lastComposedWord.mTypedWord, lastComposedWord.mCommittedWord)) { - return false; - } - if (!mDictionaryFacilitator.isUserDictionaryEnabled()) { - return false; - } - return !mDictionaryFacilitator.isValidWord(lastComposedWord.mTypedWord, - true /* ignoreCase */); - } } diff --git a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java index eba9654a5..3348a3767 100644 --- a/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java +++ b/java/src/com/android/inputmethod/latin/makedict/FormatSpec.java @@ -17,7 +17,7 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import java.util.Date; import java.util.HashMap; @@ -186,7 +186,7 @@ public final class FormatSpec { // TODO: Make this value adaptative to content data, store it in the header, and // use it in the reading code. - static final int MAX_WORD_LENGTH = Constants.DICTIONARY_MAX_WORD_LENGTH; + static final int MAX_WORD_LENGTH = DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; // These flags are used only in the static dictionary. static final int MASK_CHILDREN_ADDRESS_TYPE = 0xC0; diff --git a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java b/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java deleted file mode 100644 index f663fe96a..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/ContextualDictionary.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import android.content.Context; - -import com.android.inputmethod.annotations.ExternallyReferenced; -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; - -import java.io.File; -import java.util.Locale; - -import javax.annotation.Nullable; - -public class ContextualDictionary extends ExpandableBinaryDictionary { - /* package */ static final String NAME = ContextualDictionary.class.getSimpleName(); - - private ContextualDictionary(final Context context, final Locale locale, - final File dictFile) { - super(context, getDictName(NAME, locale, dictFile), locale, Dictionary.TYPE_CONTEXTUAL, - dictFile); - // Always reset the contents. - clear(); - } - - // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. - @SuppressWarnings("unused") - @ExternallyReferenced - public static ContextualDictionary getDictionary(final Context context, final Locale locale, - final File dictFile, final String dictNamePrefix, @Nullable final String account) { - return new ContextualDictionary(context, locale, dictFile); - } - - @Override - public boolean isValidWord(final String word) { - // Strings out of this dictionary should not be considered existing words. - return false; - } - - @Override - protected void loadInitialContentsLocked() { - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java index e974f3320..0c5e5d010 100644 --- a/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java +++ b/java/src/com/android/inputmethod/latin/personalization/DictionaryDecayBroadcastReciever.java @@ -84,7 +84,6 @@ public class DictionaryDecayBroadcastReciever extends BroadcastReceiver { final String action = intent.getAction(); if (action.equals(DICTIONARY_DECAY_INTENT_ACTION)) { PersonalizationHelper.runGCOnAllOpenedUserHistoryDictionaries(); - PersonalizationHelper.runGCOnAllOpenedPersonalizationDictionaries(); } } } diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDataChunk.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDataChunk.java deleted file mode 100644 index 734ed5583..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDataChunk.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import java.util.Collections; -import java.util.List; - -public class PersonalizationDataChunk { - public static final String LANGUAGE_UNKNOWN = ""; - - public final boolean mInputByUser; - public final List<String> mTokens; - public final int mTimestampInSeconds; - public final String mPackageName; - public final String mDetectedLanguage; - - public PersonalizationDataChunk(boolean inputByUser, final List<String> tokens, - final int timestampInSeconds, final String packageName, final String detectedLanguage) { - mInputByUser = inputByUser; - mTokens = Collections.unmodifiableList(tokens); - mTimestampInSeconds = timestampInSeconds; - mPackageName = packageName; - mDetectedLanguage = detectedLanguage; - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java deleted file mode 100644 index 76451cc6b..000000000 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionary.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2013 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.personalization; - -import android.content.Context; - -import com.android.inputmethod.annotations.ExternallyReferenced; -import com.android.inputmethod.latin.Dictionary; - -import java.io.File; -import java.util.Locale; - -import javax.annotation.Nullable; - -public class PersonalizationDictionary extends DecayingExpandableBinaryDictionaryBase { - /* package */ static final String NAME = PersonalizationDictionary.class.getSimpleName(); - - // TODO: Make this constructor private - /* package */ PersonalizationDictionary(final Context context, final Locale locale) { - super(context, getDictName(NAME, locale, null /* dictFile */), locale, - Dictionary.TYPE_PERSONALIZATION, null /* dictFile */); - } - - // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. - @SuppressWarnings("unused") - @ExternallyReferenced - public static PersonalizationDictionary getDictionary(final Context context, - final Locale locale, final File dictFile, final String dictNamePrefix, - @Nullable final String account) { - return PersonalizationHelper.getPersonalizationDictionary(context, locale); - } -} diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java index 4231450c1..1c1cb4f95 100644 --- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java +++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationHelper.java @@ -32,8 +32,7 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary} and - * {@link PersonalizationDictionary}. + * Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary}. */ public class PersonalizationHelper { private static final String TAG = PersonalizationHelper.class.getSimpleName(); @@ -41,8 +40,6 @@ public class PersonalizationHelper { private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>> sLangUserHistoryDictCache = new ConcurrentHashMap<>(); - private static final ConcurrentHashMap<String, SoftReference<PersonalizationDictionary>> - sLangPersonalizationDictCache = new ConcurrentHashMap<>(); @Nonnull public static UserHistoryDictionary getUserHistoryDictionary( @@ -77,7 +74,6 @@ public class PersonalizationHelper { DictionaryDecayBroadcastReciever.DICTIONARY_DECAY_INTERVAL_IN_MILLIS) < currentTimestamp - sCurrentTimestampForTesting) { runGCOnAllOpenedUserHistoryDictionaries(); - runGCOnAllOpenedPersonalizationDictionaries(); } } @@ -85,10 +81,6 @@ public class PersonalizationHelper { runGCOnAllDictionariesIfRequired(sLangUserHistoryDictCache); } - public static void runGCOnAllOpenedPersonalizationDictionaries() { - runGCOnAllDictionariesIfRequired(sLangPersonalizationDictCache); - } - private static <T extends DecayingExpandableBinaryDictionaryBase> void runGCOnAllDictionariesIfRequired( final ConcurrentHashMap<String, SoftReference<T>> dictionaryMap) { @@ -103,32 +95,6 @@ public class PersonalizationHelper { } } - public static PersonalizationDictionary getPersonalizationDictionary( - final Context context, final Locale locale) { - final String localeStr = locale.toString(); - synchronized (sLangPersonalizationDictCache) { - if (sLangPersonalizationDictCache.containsKey(localeStr)) { - final SoftReference<PersonalizationDictionary> ref = - sLangPersonalizationDictCache.get(localeStr); - final PersonalizationDictionary dict = ref == null ? null : ref.get(); - if (dict != null) { - if (DEBUG) { - Log.w(TAG, "Use cached PersonalizationDictionary for " + locale); - } - return dict; - } - } - final PersonalizationDictionary dict = new PersonalizationDictionary(context, locale); - sLangPersonalizationDictCache.put(localeStr, new SoftReference<>(dict)); - return dict; - } - } - - public static void removeAllPersonalizationDictionaries(final Context context) { - removeAllDictionaries(context, sLangPersonalizationDictCache, - PersonalizationDictionary.NAME); - } - public static void removeAllUserHistoryDictionaries(final Context context) { removeAllDictionaries(context, sLangUserHistoryDictCache, UserHistoryDictionary.NAME); diff --git a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java index 2e41027a4..1d75a3098 100644 --- a/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java +++ b/java/src/com/android/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -17,17 +17,14 @@ package com.android.inputmethod.latin.personalization; import android.content.Context; -import android.content.SharedPreferences; -import android.preference.PreferenceManager; import com.android.inputmethod.annotations.ExternallyReferenced; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.Dictionary; import com.android.inputmethod.latin.ExpandableBinaryDictionary; import com.android.inputmethod.latin.NgramContext; -import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.define.ProductionFlags; -import com.android.inputmethod.latin.settings.LocalSettingsConstants; import com.android.inputmethod.latin.utils.DistracterFilter; import java.io.File; @@ -102,7 +99,7 @@ public class UserHistoryDictionary extends DecayingExpandableBinaryDictionaryBas public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, @Nonnull final NgramContext ngramContext, final String word, final boolean isValid, final int timestamp, @Nonnull final DistracterFilter distracterFilter) { - if (word.length() > Constants.DICTIONARY_MAX_WORD_LENGTH) { + if (word.length() > DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH) { return; } userHistoryDictionary.updateEntriesForWordWithCheckingDistracter(ngramContext, word, diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index a080515dd..9a1bb7784 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -102,9 +102,6 @@ public class SettingsValues { private final boolean mSuggestionsEnabledPerUserSettings; private final AsyncResultHolder<AppWorkaroundsUtils> mAppWorkarounds; - // TextDecorator - public final int mTextHighlightColorForAddToDictionaryIndicator; - // Debug settings public final boolean mIsInternal; public final boolean mHasCustomKeyPreviewAnimationParams; @@ -183,8 +180,6 @@ public class SettingsValues { mAutoCorrectionEnabledPerUserSettings = mAutoCorrectEnabled && !mInputAttributes.mInputTypeNoAutoCorrect; mSuggestionsEnabledPerUserSettings = readSuggestionsEnabled(prefs); - mTextHighlightColorForAddToDictionaryIndicator = res.getColor( - R.color.text_decorator_add_to_dictionary_indicator_text_highlight_color); mIsInternal = Settings.isInternal(prefs); mHasCustomKeyPreviewAnimationParams = prefs.getBoolean( DebugSettings.PREF_HAS_CUSTOM_KEY_PREVIEW_ANIMATION_PARAMS, false); @@ -431,8 +426,6 @@ public class SettingsValues { sb.append("\n mAppWorkarounds = "); final AppWorkaroundsUtils awu = mAppWorkarounds.get(null, 0); sb.append("" + (null == awu ? "null" : awu.toString())); - sb.append("\n mTextHighlightColorForAddToDictionaryIndicator = "); - sb.append("" + mTextHighlightColorForAddToDictionaryIndicator); sb.append("\n mIsInternal = "); sb.append("" + mIsInternal); sb.append("\n mKeyPreviewShowUpDuration = "); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 8744020b1..02151522d 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -27,6 +27,7 @@ import android.view.textservice.SuggestionsInfo; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.keyboard.KeyboardLayoutSet; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.DictionaryFacilitator; @@ -34,6 +35,7 @@ import com.android.inputmethod.latin.DictionaryFacilitatorLruCache; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.RichInputMethodSubtype; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.ScriptUtils; @@ -65,10 +67,8 @@ public final class AndroidSpellCheckerService extends SpellCheckerService // TODO: Make each spell checker session has its own session id. private final ConcurrentLinkedQueue<Integer> mSessionIdPool = new ConcurrentLinkedQueue<>(); - private static final int MAX_DICTIONARY_FACILITATOR_COUNT = 3; private final DictionaryFacilitatorLruCache mDictionaryFacilitatorCache = - new DictionaryFacilitatorLruCache(this /* context */, MAX_DICTIONARY_FACILITATOR_COUNT, - DICTIONARY_NAME_PREFIX); + new DictionaryFacilitatorLruCache(this /* context */, DICTIONARY_NAME_PREFIX); private final ConcurrentHashMap<Locale, Keyboard> mKeyboardCache = new ConcurrentHashMap<>(); // The threshold for a suggestion to be considered "recommended". @@ -152,14 +152,15 @@ public final class AndroidSpellCheckerService extends SpellCheckerService try { DictionaryFacilitator dictionaryFacilitatorForLocale = mDictionaryFacilitatorCache.get(locale); - return dictionaryFacilitatorForLocale.isValidWord(word, false /* igroreCase */); + return dictionaryFacilitatorForLocale.isValidSpellingWord(word); } finally { mSemaphore.release(); } } public SuggestionResults getSuggestionResults(final Locale locale, final WordComposer composer, - final NgramContext ngramContext, final ProximityInfo proximityInfo) { + final NgramContext ngramContext, final ProximityInfo proximityInfo, + final KeyboardLayout keyboardLayout) { Integer sessionId = null; mSemaphore.acquireUninterruptibly(); try { @@ -168,7 +169,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService mDictionaryFacilitatorCache.get(locale); return dictionaryFacilitatorForLocale.getSuggestionResults(composer, ngramContext, proximityInfo.getNativeProximityInfo(), mSettingsValuesForSuggestion, - sessionId); + sessionId, SuggestedWords.INPUT_STYLE_TYPING, keyboardLayout); } finally { if (sessionId != null) { mSessionIdPool.add(sessionId); diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 832bfd066..0b5e12f03 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -29,6 +29,7 @@ import android.view.textservice.TextInfo; import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardLayout; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; @@ -271,18 +272,21 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { final int[] codePoints = StringUtils.toCodePointArray(text); final int[] coordinates; final ProximityInfo proximityInfo; + final KeyboardLayout keyboardLayout; if (null == keyboard) { coordinates = CoordinateUtils.newCoordinateArray(codePoints.length, Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE); proximityInfo = null; + keyboardLayout = null; } else { coordinates = keyboard.getCoordinates(codePoints); proximityInfo = keyboard.getProximityInfo(); + keyboardLayout = keyboard.getKeyboardLayout(); } composer.setComposingWord(codePoints, coordinates); // TODO: Don't gather suggestions if the limit is <= 0 unless necessary final SuggestionResults suggestionResults = mService.getSuggestionResults( - mLocale, composer, ngramContext, proximityInfo); + mLocale, composer, ngramContext, proximityInfo, keyboardLayout); final Result result = getResult(capitalizeType, mLocale, suggestionsLimit, mService.getRecommendedThreshold(), text, suggestionResults); isInDict = isInDictForAnyCapitalization(text, capitalizeType); diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 7991a2473..a9d1207f1 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -28,7 +28,6 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; -import android.support.v4.view.ViewCompat; import android.text.Spannable; import android.text.SpannableString; import android.text.Spanned; @@ -50,7 +49,6 @@ import com.android.inputmethod.latin.PunctuationSuggestions; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import com.android.inputmethod.latin.common.LocaleUtils; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.SettingsValues; import com.android.inputmethod.latin.utils.ResourceUtils; @@ -95,8 +93,6 @@ final class SuggestionStripLayoutHelper { private final int mTypedWordPositionWhenAutocorrect; private final Drawable mMoreSuggestionsHint; private static final String MORE_SUGGESTIONS_HINT = "\u2026"; - private static final String LEFTWARDS_ARROW = "\u2190"; - private static final String RIGHTWARDS_ARROW = "\u2192"; private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); @@ -540,55 +536,6 @@ final class SuggestionStripLayoutHelper { return countInStrip; } - public void layoutAddToDictionaryHint(final String word, final ViewGroup addToDictionaryStrip, - final boolean shouldShowWordToSave) { - final boolean showsHintWithWord = shouldShowWordToSave - || !Settings.getInstance().getCurrent().mShouldShowLxxSuggestionUi; - final int stripWidth = addToDictionaryStrip.getWidth(); - final int width = stripWidth - (showsHintWithWord ? mDividerWidth + mPadding * 2 : 0); - - final TextView wordView = (TextView)addToDictionaryStrip.findViewById(R.id.word_to_save); - wordView.setTextColor(mColorTypedWord); - final int wordWidth = (int)(width * mCenterSuggestionWeight); - final CharSequence wordToSave = getEllipsizedTextWithSettingScaleX( - word, wordWidth, wordView.getPaint()); - final float wordScaleX = wordView.getTextScaleX(); - wordView.setText(wordToSave); - wordView.setTextScaleX(wordScaleX); - setLayoutWeight(wordView, mCenterSuggestionWeight, ViewGroup.LayoutParams.MATCH_PARENT); - final int wordVisibility = showsHintWithWord ? View.VISIBLE : View.GONE; - wordView.setVisibility(wordVisibility); - addToDictionaryStrip.findViewById(R.id.word_to_save_divider).setVisibility(wordVisibility); - - final Resources res = addToDictionaryStrip.getResources(); - final CharSequence hintText; - final int hintWidth; - final float hintWeight; - final TextView hintView = (TextView)addToDictionaryStrip.findViewById( - R.id.hint_add_to_dictionary); - if (showsHintWithWord) { - final boolean isRtlLanguage = (ViewCompat.getLayoutDirection(addToDictionaryStrip) - == ViewCompat.LAYOUT_DIRECTION_RTL); - final String arrow = isRtlLanguage ? RIGHTWARDS_ARROW : LEFTWARDS_ARROW; - final boolean isRtlSystem = LocaleUtils.isRtlLanguage(res.getConfiguration().locale); - final CharSequence hint = res.getText(R.string.hint_add_to_dictionary); - hintText = (isRtlLanguage == isRtlSystem) ? (arrow + hint) : (hint + arrow); - hintWidth = width - wordWidth; - hintWeight = 1.0f - mCenterSuggestionWeight; - hintView.setGravity(Gravity.CENTER_VERTICAL | Gravity.START); - } else { - hintText = res.getText(R.string.hint_add_to_dictionary_without_word); - hintWidth = width; - hintWeight = 1.0f; - hintView.setGravity(Gravity.CENTER); - } - hintView.setTextColor(mColorAutoCorrect); - final float hintScaleX = getTextScaleX(hintText, hintWidth, hintView.getPaint()); - hintView.setText(hintText); // TextView.setText() resets text scale x to 1.0. - hintView.setTextScaleX(hintScaleX); - setLayoutWeight(hintView, hintWeight, ViewGroup.LayoutParams.MATCH_PARENT); - } - public void layoutImportantNotice(final View importantNoticeStrip, final String importantNoticeTitle) { final TextView titleView = (TextView)importantNoticeStrip.findViewById( diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java index b71bd1f50..4b849496c 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripView.java @@ -58,7 +58,6 @@ import java.util.ArrayList; public final class SuggestionStripView extends RelativeLayout implements OnClickListener, OnLongClickListener { public interface Listener { - public void addWordToUserDictionary(String word); public void showImportantNoticeContents(); public void pickSuggestionManually(SuggestedWordInfo word); public void onCodeInput(int primaryCode, int x, int y, boolean isKeyRepeat); @@ -69,7 +68,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick private final ViewGroup mSuggestionsStrip; private final ImageButton mVoiceKey; - private final ViewGroup mAddToDictionaryStrip; private final View mImportantNoticeStrip; MainKeyboardView mMainKeyboardView; @@ -91,15 +89,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick private static class StripVisibilityGroup { private final View mSuggestionStripView; private final View mSuggestionsStrip; - private final View mAddToDictionaryStrip; private final View mImportantNoticeStrip; public StripVisibilityGroup(final View suggestionStripView, - final ViewGroup suggestionsStrip, final ViewGroup addToDictionaryStrip, - final View importantNoticeStrip) { + final ViewGroup suggestionsStrip, final View importantNoticeStrip) { mSuggestionStripView = suggestionStripView; mSuggestionsStrip = suggestionsStrip; - mAddToDictionaryStrip = addToDictionaryStrip; mImportantNoticeStrip = importantNoticeStrip; showSuggestionsStrip(); } @@ -109,35 +104,22 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick : ViewCompat.LAYOUT_DIRECTION_LTR; ViewCompat.setLayoutDirection(mSuggestionStripView, layoutDirection); ViewCompat.setLayoutDirection(mSuggestionsStrip, layoutDirection); - ViewCompat.setLayoutDirection(mAddToDictionaryStrip, layoutDirection); ViewCompat.setLayoutDirection(mImportantNoticeStrip, layoutDirection); } public void showSuggestionsStrip() { mSuggestionsStrip.setVisibility(VISIBLE); - mAddToDictionaryStrip.setVisibility(INVISIBLE); - mImportantNoticeStrip.setVisibility(INVISIBLE); - } - - public void showAddToDictionaryStrip() { - mSuggestionsStrip.setVisibility(INVISIBLE); - mAddToDictionaryStrip.setVisibility(VISIBLE); mImportantNoticeStrip.setVisibility(INVISIBLE); } public void showImportantNoticeStrip() { mSuggestionsStrip.setVisibility(INVISIBLE); - mAddToDictionaryStrip.setVisibility(INVISIBLE); mImportantNoticeStrip.setVisibility(VISIBLE); } public boolean isShowingImportantNoticeStrip() { return mImportantNoticeStrip.getVisibility() == VISIBLE; } - - public boolean isShowingAddToDictionaryStrip() { - return mAddToDictionaryStrip.getVisibility() == VISIBLE; - } } /** @@ -158,10 +140,9 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mSuggestionsStrip = (ViewGroup)findViewById(R.id.suggestions_strip); mVoiceKey = (ImageButton)findViewById(R.id.suggestions_strip_voice_key); - mAddToDictionaryStrip = (ViewGroup)findViewById(R.id.add_to_dictionary_strip); mImportantNoticeStrip = findViewById(R.id.important_notice_strip); mStripVisibilityGroup = new StripVisibilityGroup(this, mSuggestionsStrip, - mAddToDictionaryStrip, mImportantNoticeStrip); + mImportantNoticeStrip); for (int pos = 0; pos < SuggestedWords.MAX_SUGGESTIONS; pos++) { final TextView word = new TextView(context, null, R.attr.suggestionWordStyle); @@ -227,27 +208,6 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick mLayoutHelper.setMoreSuggestionsHeight(remainingHeight); } - public boolean isShowingAddToDictionaryHint() { - return mStripVisibilityGroup.isShowingAddToDictionaryStrip(); - } - - public void showAddToDictionaryHint(final String word, final boolean shouldShowWordToSave) { - mLayoutHelper.layoutAddToDictionaryHint(word, mAddToDictionaryStrip, shouldShowWordToSave); - // {@link TextView#setTag()} is used to hold the word to be added to dictionary. The word - // will be extracted at {@link #onClick(View)}. - mAddToDictionaryStrip.setTag(word); - mAddToDictionaryStrip.setOnClickListener(this); - mStripVisibilityGroup.showAddToDictionaryStrip(); - } - - public boolean dismissAddToDictionaryHint() { - if (isShowingAddToDictionaryHint()) { - clear(); - return true; - } - return false; - } - // This method checks if we should show the important notice (checks on permanent storage if // it has been shown once already or not, and if in the setup wizard). If applicable, it shows // the notice. In all cases, it returns true if it was shown, false otherwise. @@ -494,15 +454,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick false /* isKeyRepeat */); return; } - final Object tag = view.getTag(); - // {@link String} tag is set at {@link #suggestAddingToDictionary(String,CharSequence)}. - if (tag instanceof String) { - final String wordToSave = (String)tag; - mListener.addWordToUserDictionary(wordToSave); - clear(); - return; - } + final Object tag = view.getTag(); // {@link Integer} tag is set at // {@link SuggestionStripLayoutHelper#setupWordViewsTextAndColor(SuggestedWords,int)} and // {@link SuggestionStripLayoutHelper#layoutPunctuationSuggestions(SuggestedWords,ViewGroup} diff --git a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java index 5c86a02af..68f417e84 100644 --- a/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java +++ b/java/src/com/android/inputmethod/latin/suggestions/SuggestionStripViewAccessor.java @@ -22,9 +22,6 @@ import com.android.inputmethod.latin.SuggestedWords; * An object that gives basic control of a suggestion strip and some info on it. */ public interface SuggestionStripViewAccessor { - public void suggestAddingToDictionary(final String word, final boolean isFromSuggestionStrip); - public boolean isShowingAddToDictionaryHint(); - public void dismissAddToDictionaryHint(); public void setNeutralSuggestionStrip(); public void showSuggestionStrip(final SuggestedWords suggestedWords); } diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java deleted file mode 100644 index 163443036..000000000 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionaryAddWordFragment.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (C) 2013 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.userdictionary; - -import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordContents.LocaleRenderer; -import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker.LocationChangedListener; - -import android.app.Fragment; -import android.os.Bundle; -import android.preference.PreferenceActivity; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Spinner; - -import java.util.ArrayList; -import java.util.Locale; - -// Caveat: This class is basically taken from -// packages/apps/Settings/src/com/android/settings/inputmethod/UserDictionaryAddWordFragment.java -// in order to deal with some devices that have issues with the user dictionary handling - -/** - * Fragment to add a word/shortcut to the user dictionary. - * - * As opposed to the UserDictionaryActivity, this is only invoked within Settings - * from the UserDictionarySettings. - */ -public class UserDictionaryAddWordFragment extends Fragment - implements AdapterView.OnItemSelectedListener, LocationChangedListener { - - private static final int OPTIONS_MENU_ADD = Menu.FIRST; - private static final int OPTIONS_MENU_DELETE = Menu.FIRST + 1; - - private UserDictionaryAddWordContents mContents; - private View mRootView; - private boolean mIsDeleting = false; - - @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - setHasOptionsMenu(true); - getActivity().getActionBar().setTitle(R.string.edit_personal_dictionary); - // Keep the instance so that we remember mContents when configuration changes (eg rotation) - setRetainInstance(true); - } - - @Override - public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedState) { - mRootView = inflater.inflate(R.layout.user_dictionary_add_word_fullscreen, null); - mIsDeleting = false; - // If we have a non-null mContents object, it's the old value before a configuration - // change (eg rotation) so we need to use its values. Otherwise, read from the arguments. - if (null == mContents) { - mContents = new UserDictionaryAddWordContents(mRootView, getArguments()); - } else { - // We create a new mContents object to account for the new situation : a word has - // been added to the user dictionary when we started rotating, and we are now editing - // it. That means in particular if the word undergoes any change, the old version should - // be updated, so the mContents object needs to switch to EDIT mode if it was in - // INSERT mode. - mContents = new UserDictionaryAddWordContents(mRootView, - mContents /* oldInstanceToBeEdited */); - } - getActivity().getActionBar().setSubtitle(UserDictionarySettingsUtils.getLocaleDisplayName( - getActivity(), mContents.getCurrentUserDictionaryLocale())); - return mRootView; - } - - @Override - public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { - final MenuItem actionItemAdd = menu.add(0, OPTIONS_MENU_ADD, 0, - R.string.user_dict_settings_add_menu_title).setIcon(R.drawable.ic_menu_add); - actionItemAdd.setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - final MenuItem actionItemDelete = menu.add(0, OPTIONS_MENU_DELETE, 0, - R.string.user_dict_settings_delete).setIcon(android.R.drawable.ic_menu_delete); - actionItemDelete.setShowAsAction( - MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT); - } - - /** - * Callback for the framework when a menu option is pressed. - * - * @param item the item that was pressed - * @return false to allow normal menu processing to proceed, true to consume it here - */ - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == OPTIONS_MENU_ADD) { - // added the entry in "onPause" - getActivity().onBackPressed(); - return true; - } - if (item.getItemId() == OPTIONS_MENU_DELETE) { - mContents.delete(getActivity()); - mIsDeleting = true; - getActivity().onBackPressed(); - return true; - } - return false; - } - - @Override - public void onResume() { - super.onResume(); - // We are being shown: display the word - updateSpinner(); - } - - private void updateSpinner() { - final ArrayList<LocaleRenderer> localesList = mContents.getLocalesList(getActivity()); - - final Spinner localeSpinner = - (Spinner)mRootView.findViewById(R.id.user_dictionary_add_locale); - final ArrayAdapter<LocaleRenderer> adapter = new ArrayAdapter<>( - getActivity(), android.R.layout.simple_spinner_item, localesList); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - localeSpinner.setAdapter(adapter); - localeSpinner.setOnItemSelectedListener(this); - } - - @Override - public void onPause() { - super.onPause(); - // We are being hidden: commit changes to the user dictionary, unless we were deleting it - if (!mIsDeleting) { - mContents.apply(getActivity(), null); - } - } - - @Override - public void onItemSelected(final AdapterView<?> parent, final View view, final int pos, - final long id) { - final LocaleRenderer locale = (LocaleRenderer)parent.getItemAtPosition(pos); - if (locale.isMoreLanguages()) { - PreferenceActivity preferenceActivity = (PreferenceActivity)getActivity(); - preferenceActivity.startPreferenceFragment(new UserDictionaryLocalePicker(), true); - } else { - mContents.updateLocale(locale.getLocaleString()); - } - } - - @Override - public void onNothingSelected(final AdapterView<?> parent) { - // I'm not sure we can come here, but if we do, that's the right thing to do. - final Bundle args = getArguments(); - mContents.updateLocale(args.getString(UserDictionaryAddWordContents.EXTRA_LOCALE)); - } - - // Called by the locale picker - @Override - public void onLocaleSelected(final Locale locale) { - mContents.updateLocale(locale.toString()); - getActivity().onBackPressed(); - } -} diff --git a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java index 1d7e7d683..fabd49f46 100644 --- a/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java +++ b/java/src/com/android/inputmethod/latin/userdictionary/UserDictionarySettings.java @@ -240,8 +240,6 @@ public class UserDictionarySettings extends ListFragment { args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale); android.preference.PreferenceActivity pa = (android.preference.PreferenceActivity)getActivity(); - pa.startPreferencePanel(UserDictionaryAddWordFragment.class.getName(), - args, R.string.user_dict_settings_add_dialog_title, null, null, 0); } private String getWord(final int position) { diff --git a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java index fcce1ecdd..e355b7e1f 100644 --- a/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/DictionaryInfoUtils.java @@ -27,8 +27,8 @@ import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.AssetFileAddress; import com.android.inputmethod.latin.BinaryDictionaryGetter; import com.android.inputmethod.latin.R; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.LocaleUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.UnsupportedFormatException; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; @@ -450,7 +450,7 @@ public class DictionaryInfoUtils { return false; } final int length = text.length(); - if (length > Constants.DICTIONARY_MAX_WORD_LENGTH) { + if (length > DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH) { return false; } int i = 0; diff --git a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java index 56a04a856..becf13fd9 100644 --- a/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java +++ b/java/src/com/android/inputmethod/latin/utils/DistracterFilterCheckingExactMatchesAndSuggestions.java @@ -38,6 +38,7 @@ import com.android.inputmethod.latin.DictionaryFacilitator; import com.android.inputmethod.latin.DictionaryFacilitatorLruCache; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.RichInputMethodSubtype; +import com.android.inputmethod.latin.SuggestedWords; import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo; import com.android.inputmethod.latin.WordComposer; import com.android.inputmethod.latin.common.StringUtils; @@ -52,7 +53,6 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr DistracterFilterCheckingExactMatchesAndSuggestions.class.getSimpleName(); private static final boolean DEBUG = false; - private static final int MAX_DICTIONARY_FACILITATOR_CACHE_SIZE = 3; private static final int MAX_DISTRACTERS_CACHE_SIZE = 1024; private final Context mContext; @@ -80,8 +80,8 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr mContext = context; mLocaleToSubtypeCache = new ConcurrentHashMap<>(); mLocaleToKeyboardCache = new ConcurrentHashMap<>(); - mDictionaryFacilitatorLruCache = new DictionaryFacilitatorLruCache(context, - MAX_DICTIONARY_FACILITATOR_CACHE_SIZE, "" /* dictionaryNamePrefix */); + mDictionaryFacilitatorLruCache = new DictionaryFacilitatorLruCache( + context, "" /* dictionaryNamePrefix */); mDistractersCache = new LruCache<>(MAX_DISTRACTERS_CACHE_SIZE); } @@ -195,8 +195,7 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr mDistractersCache.put(cacheKey, Boolean.TRUE); return true; } - final boolean Word = dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */); - if (Word) { + if (dictionaryFacilitator.isValidSuggestionWord(testedWord)) { // Valid word is not a distracter. if (DEBUG) { Log.d(TAG, "isDistracter: false (valid word)"); @@ -252,7 +251,9 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr suggestionResults = dictionaryFacilitator.getSuggestionResults(composer, NgramContext.EMPTY_PREV_WORDS_INFO, keyboard.getProximityInfo().getNativeProximityInfo(), - settingsValuesForSuggestion, 0 /* sessionId */); + settingsValuesForSuggestion, 0 /* sessionId */, + SuggestedWords.INPUT_STYLE_TYPING, + keyboard.getKeyboardLayout()); } if (suggestionResults.isEmpty()) { return false; @@ -288,14 +289,14 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr final Locale locale) { final DictionaryFacilitator dictionaryFacilitator = mDictionaryFacilitatorLruCache.get(locale); - if (dictionaryFacilitator.isValidWord(testedWord, false /* ignoreCase */)) { + if (dictionaryFacilitator.isValidSuggestionWord(testedWord)) { return false; } - final String lowerCaseTargetWord = testedWord.toLowerCase(locale); - if (testedWord.equals(lowerCaseTargetWord)) { + final String lowerCaseWord = testedWord.toLowerCase(locale); + if (testedWord.equals(lowerCaseWord)) { return false; } - if (dictionaryFacilitator.isValidWord(lowerCaseTargetWord, false /* ignoreCase */)) { + if (dictionaryFacilitator.isValidSuggestionWord(lowerCaseWord)) { return true; } if (StringUtils.getCapitalizationType(testedWord) == StringUtils.CAPITALIZE_FIRST @@ -314,10 +315,10 @@ public class DistracterFilterCheckingExactMatchesAndSuggestions implements Distr return HandlingType.getHandlingType(false /* shouldBeLowerCased */, false /* isOov */); } final boolean shouldBeLowerCased = shouldBeLowerCased(ngramContext, testedWord, locale); - final String caseModifiedWord = - shouldBeLowerCased ? testedWord.toLowerCase(locale) : testedWord; - final boolean isOov = !mDictionaryFacilitatorLruCache.get(locale).isValidWord( - caseModifiedWord, false /* ignoreCase */); + final String caseModifiedWord = shouldBeLowerCased + ? testedWord.toLowerCase(locale) : testedWord; + final boolean isOov = !mDictionaryFacilitatorLruCache.get(locale).isValidSuggestionWord( + caseModifiedWord); return HandlingType.getHandlingType(shouldBeLowerCased, isOov); } } diff --git a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java index 147e57b13..c87a7c05c 100644 --- a/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/FragmentUtils.java @@ -29,7 +29,6 @@ import com.android.inputmethod.latin.settings.PreferencesSettingsFragment; import com.android.inputmethod.latin.settings.SettingsFragment; import com.android.inputmethod.latin.settings.ThemeSettingsFragment; import com.android.inputmethod.latin.spellcheck.SpellCheckerSettingsFragment; -import com.android.inputmethod.latin.userdictionary.UserDictionaryAddWordFragment; import com.android.inputmethod.latin.userdictionary.UserDictionaryList; import com.android.inputmethod.latin.userdictionary.UserDictionaryLocalePicker; import com.android.inputmethod.latin.userdictionary.UserDictionarySettings; @@ -52,7 +51,6 @@ public class FragmentUtils { sLatinImeFragments.add(DebugSettingsFragment.class.getName()); sLatinImeFragments.add(SettingsFragment.class.getName()); sLatinImeFragments.add(SpellCheckerSettingsFragment.class.getName()); - sLatinImeFragments.add(UserDictionaryAddWordFragment.class.getName()); sLatinImeFragments.add(UserDictionaryList.class.getName()); sLatinImeFragments.add(UserDictionaryLocalePicker.class.getName()); sLatinImeFragments.add(UserDictionarySettings.class.getName()); diff --git a/java/src/com/android/inputmethod/latin/utils/NgramContextUtils.java b/java/src/com/android/inputmethod/latin/utils/NgramContextUtils.java index 7d2ddd268..727df1a93 100644 --- a/java/src/com/android/inputmethod/latin/utils/NgramContextUtils.java +++ b/java/src/com/android/inputmethod/latin/utils/NgramContextUtils.java @@ -18,7 +18,7 @@ package com.android.inputmethod.latin.utils; import com.android.inputmethod.latin.NgramContext; import com.android.inputmethod.latin.NgramContext.WordInfo; -import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import java.util.Arrays; @@ -59,7 +59,8 @@ public final class NgramContextUtils { final SpacingAndPunctuations spacingAndPunctuations, final int n) { if (prev == null) return NgramContext.EMPTY_PREV_WORDS_INFO; final String[] w = SPACE_REGEX.split(prev); - final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + final WordInfo[] prevWordsInfo = + new WordInfo[DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; Arrays.fill(prevWordsInfo, WordInfo.EMPTY_WORD_INFO); for (int i = 0; i < prevWordsInfo.length; i++) { final int focusedWordIndex = w.length - n - i; diff --git a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java index b319aeb8a..10e3994b6 100644 --- a/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java +++ b/java/src/com/android/inputmethod/latin/utils/SuggestionResults.java @@ -33,14 +33,21 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { // TODO: Instead of a boolean , we may want to include the context of this suggestion results, // such as {@link NgramContext}. public final boolean mIsBeginningOfSentence; + public final boolean mAutocorrectRecommendation; private final int mCapacity; public SuggestionResults(final int capacity, final boolean isBeginningOfSentence) { - this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence); + this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence, false); } - private SuggestionResults(final Comparator<SuggestedWordInfo> comparator, - final int capacity, final boolean isBeginningOfSentence) { + public SuggestionResults(final int capacity, final boolean isBeginningOfSentence, + final boolean autocorrectRecommendation) { + this(sSuggestedWordInfoComparator, capacity, isBeginningOfSentence, + autocorrectRecommendation); + } + + private SuggestionResults(final Comparator<SuggestedWordInfo> comparator, final int capacity, + final boolean isBeginningOfSentence, final boolean autocorrectRecommendation) { super(comparator); mCapacity = capacity; if (ProductionFlags.INCLUDE_RAW_SUGGESTIONS) { @@ -49,6 +56,7 @@ public final class SuggestionResults extends TreeSet<SuggestedWordInfo> { mRawSuggestions = null; } mIsBeginningOfSentence = isBeginningOfSentence; + mAutocorrectRecommendation = autocorrectRecommendation; } @Override diff --git a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java index 86a5b19ec..e9a0e7a61 100644 --- a/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java +++ b/java/src/com/android/inputmethod/latin/utils/WordInputEventForPersonalization.java @@ -20,8 +20,8 @@ import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.latin.NgramContext; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.StringUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.settings.SpacingAndPunctuations; import com.android.inputmethod.latin.utils.DistracterFilter.HandlingType; @@ -37,9 +37,10 @@ public final class WordInputEventForPersonalization { public final int[] mTargetWord; public final int mPrevWordsCount; - public final int[][] mPrevWordArray = new int[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][]; + public final int[][] mPrevWordArray = + new int[DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM][]; public final boolean[] mIsPrevWordBeginningOfSentenceArray = - new boolean[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; + new boolean[DecoderSpecificConstants.MAX_PREV_WORD_COUNT_FOR_N_GRAM]; public final boolean mIsValid; // Time stamp in seconds. public final int mTimestamp; diff --git a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java index 9aced5cea..733bf96e2 100644 --- a/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java +++ b/tests/src/com/android/inputmethod/keyboard/KeyboardLayoutTest.java @@ -45,8 +45,10 @@ public class KeyboardLayoutTest { assertEquals(0, keyboardLayout.getKeyXCoordinates().length); assertEquals(0, keyboardLayout.getKeyYCoordinates().length); - Key key1 = new Key("label1", 101, 102, "101", "101hint", 103, 104, 105, 106, 1100, 1101, 2, 2); - Key key2 = new Key("label2", 201, 202, "201", "201hint", 203, 204, 205, 206, 2100, 2201, 2, 2); + Key key1 = new Key("label1", 101, 102, "101", "101hint", 103, 104, 105, 106, 1100, 1101, + 10, 10); + Key key2 = new Key("label2", 201, 103, "201", "201hint", 203, 204, 205, 206, 2100, 2101, + 10, 10); ArrayList<Key> sortedKeys = new ArrayList<>(2); sortedKeys.add(key1); @@ -57,5 +59,23 @@ public class KeyboardLayoutTest { assertEquals(2, keyboardLayout.getKeyHeights().length); assertEquals(2, keyboardLayout.getKeyXCoordinates().length); assertEquals(2, keyboardLayout.getKeyYCoordinates().length); + + assertEquals(102, keyboardLayout.getKeyCodes()[0]); + // xCo + horizontalGap/2 + assertEquals(105 + 5, keyboardLayout.getKeyXCoordinates()[0]); + assertEquals(106, keyboardLayout.getKeyYCoordinates()[0]); + // width - horizontalGap + assertEquals(1100 - 10, keyboardLayout.getKeyWidths()[0]); + // height - verticalGap + assertEquals(1101 - 10, keyboardLayout.getKeyHeights()[0]); + + assertEquals(103, keyboardLayout.getKeyCodes()[1]); + // xCo + horizontalGap/2 + assertEquals(205 + 5, keyboardLayout.getKeyXCoordinates()[1]); + assertEquals(206, keyboardLayout.getKeyYCoordinates()[1]); + // width - horizontalGap + assertEquals(2100 - 10, keyboardLayout.getKeyWidths()[1]); + // height - verticalGap + assertEquals(2101 - 10, keyboardLayout.getKeyHeights()[1]); } } diff --git a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java index 60d2de18c..a8f0d81af 100644 --- a/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java +++ b/tests/src/com/android/inputmethod/latin/BinaryDictionaryTests.java @@ -23,8 +23,8 @@ import android.util.Pair; import com.android.inputmethod.latin.NgramContext.WordInfo; import com.android.inputmethod.latin.common.CodePointUtils; -import com.android.inputmethod.latin.common.Constants; import com.android.inputmethod.latin.common.FileUtils; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.DictionaryHeader; import com.android.inputmethod.latin.makedict.FormatSpec; import com.android.inputmethod.latin.makedict.WeightedString; @@ -171,7 +171,7 @@ public class BinaryDictionaryTests extends AndroidTestCase { private void testAddTooLongWord(final int formatVersion) { final BinaryDictionary binaryDictionary = getEmptyBinaryDictionary(formatVersion); final StringBuffer stringBuilder = new StringBuffer(); - for (int i = 0; i < Constants.DICTIONARY_MAX_WORD_LENGTH; i++) { + for (int i = 0; i < DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; i++) { stringBuilder.append('a'); } final String validLongWord = stringBuilder.toString(); diff --git a/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java b/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java index 3ad659a99..5340b6fa7 100644 --- a/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java +++ b/tests/src/com/android/inputmethod/latin/DictionaryFacilitatorLruCacheTests.java @@ -23,12 +23,9 @@ import android.test.suitebuilder.annotation.LargeTest; @LargeTest public class DictionaryFacilitatorLruCacheTests extends AndroidTestCase { - static final int MAX_CACHE_SIZE = 2; - static final int MAX_CACHE_SIZE_LARGE = 5; - public void testCacheSize() { final DictionaryFacilitatorLruCache cache = - new DictionaryFacilitatorLruCache(getContext(), MAX_CACHE_SIZE, ""); + new DictionaryFacilitatorLruCache(getContext(), ""); assertEquals(0, cache.getCachedLocalesForTesting().size()); assertNotNull(cache.get(Locale.US)); @@ -42,12 +39,9 @@ public class DictionaryFacilitatorLruCacheTests extends AndroidTestCase { } public void testGetFacilitator() { - testGetFacilitator(new DictionaryFacilitatorLruCache(getContext(), MAX_CACHE_SIZE, "")); - testGetFacilitator(new DictionaryFacilitatorLruCache( - getContext(), MAX_CACHE_SIZE_LARGE, "")); - } + final DictionaryFacilitatorLruCache cache = + new DictionaryFacilitatorLruCache(getContext(), ""); - private static void testGetFacilitator(final DictionaryFacilitatorLruCache cache) { final DictionaryFacilitator dictionaryFacilitatorEnUs = cache.get(Locale.US); assertNotNull(dictionaryFacilitatorEnUs); assertTrue(dictionaryFacilitatorEnUs.isForLocales(new Locale[] { Locale.US })); @@ -62,13 +56,9 @@ public class DictionaryFacilitatorLruCacheTests extends AndroidTestCase { } public void testSetUseContactsDictionary() { - testSetUseContactsDictionary(new DictionaryFacilitatorLruCache( - getContext(), MAX_CACHE_SIZE, "")); - testSetUseContactsDictionary(new DictionaryFacilitatorLruCache( - getContext(), MAX_CACHE_SIZE_LARGE, "")); - } + final DictionaryFacilitatorLruCache cache = + new DictionaryFacilitatorLruCache(getContext(), ""); - private static void testSetUseContactsDictionary(final DictionaryFacilitatorLruCache cache) { assertNull(cache.get(Locale.US).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); cache.setUseContactsDictionary(true /* useContactsDictionary */); assertNotNull(cache.get(Locale.US).getSubDictForTesting(Dictionary.TYPE_CONTACTS)); diff --git a/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java b/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java new file mode 100644 index 000000000..59bb08292 --- /dev/null +++ b/tests/src/com/android/inputmethod/latin/common/UnicodeSurrogateTests.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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.common; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +@SmallTest +public class UnicodeSurrogateTests extends AndroidTestCase { + + public void testIsLowSurrogate() { + assertFalse(UnicodeSurrogate.isLowSurrogate('\uD7FF')); + assertTrue(UnicodeSurrogate.isLowSurrogate('\uD83D')); + assertFalse(UnicodeSurrogate.isLowSurrogate('\uDC00')); + } + + public void testIsHighSurrogate() { + assertFalse(UnicodeSurrogate.isHighSurrogate('\uDBFF')); + assertTrue(UnicodeSurrogate.isHighSurrogate('\uDE25')); + assertFalse(UnicodeSurrogate.isHighSurrogate('\uE000')); + } +} diff --git a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java index b104a21f9..a432ca740 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java +++ b/tests/src/com/android/inputmethod/latin/makedict/BinaryDictIOUtils.java @@ -17,7 +17,7 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory; import java.io.File; @@ -183,7 +183,7 @@ public final class BinaryDictIOUtils { dictDecoder.readHeader(); int wordPos = 0; final int wordLen = word.codePointCount(0, word.length()); - for (int depth = 0; depth < Constants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { + for (int depth = 0; depth < DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH; ++depth) { if (wordPos >= wordLen) return FormatSpec.NOT_VALID_WORD; do { diff --git a/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java b/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java index 3cffd001c..a42f0a93d 100644 --- a/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java +++ b/tests/src/com/android/inputmethod/latin/makedict/FusionDictionary.java @@ -17,7 +17,7 @@ package com.android.inputmethod.latin.makedict; import com.android.inputmethod.annotations.UsedForTesting; -import com.android.inputmethod.latin.common.Constants; +import com.android.inputmethod.latin.define.DecoderSpecificConstants; import com.android.inputmethod.latin.makedict.FormatSpec.DictionaryOptions; import java.util.ArrayList; @@ -387,7 +387,7 @@ public final class FusionDictionary implements Iterable<WordProperty> { final ArrayList<WeightedString> shortcutTargets, final boolean isNotAWord, final boolean isPossiblyOffensive) { assert(probabilityInfo.mProbability <= FormatSpec.MAX_TERMINAL_FREQUENCY); - if (word.length >= Constants.DICTIONARY_MAX_WORD_LENGTH) { + if (word.length >= DecoderSpecificConstants.DICTIONARY_MAX_WORD_LENGTH) { MakedictLog.w("Ignoring a word that is too long: word.length = " + word.length); return; } diff --git a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java deleted file mode 100644 index b9ce78d00..000000000 --- a/tests/src/com/android/inputmethod/latin/personalization/ContextualDictionaryTests.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.DictionaryFacilitator; -import com.android.inputmethod.latin.DictionaryFacilitatorProvider; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; - -/** - * Unit tests for contextual dictionary - */ -@LargeTest -public class ContextualDictionaryTests extends AndroidTestCase { - private static final Locale LOCALE_EN_US = new Locale("en", "US"); - - private DictionaryFacilitator getDictionaryFacilitator() { - final ArrayList<String> dictTypes = new ArrayList<>(); - dictTypes.add(Dictionary.TYPE_CONTEXTUAL); - final DictionaryFacilitator dictionaryFacilitator = - DictionaryFacilitatorProvider.newDictionaryFacilitator(); - dictionaryFacilitator.resetDictionariesForTesting(getContext(), - new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(), - Collections.<String, Map<String, String>>emptyMap(), null /* account */); - return dictionaryFacilitator; - } - - public void testAddPhrase() { - final DictionaryFacilitator dictionaryFacilitator = getDictionaryFacilitator(); - final String[] phrase = new String[] {"a", "b", "c", "d"}; - final int probability = 100; - final int bigramProbabilityForWords = 150; - final int bigramProbabilityForPhrases = 200; - dictionaryFacilitator.addPhraseToContextualDictionary( - phrase, probability, bigramProbabilityForWords, bigramProbabilityForPhrases); - final ExpandableBinaryDictionary contextualDictionary = - dictionaryFacilitator.getSubDictForTesting(Dictionary.TYPE_CONTEXTUAL); - contextualDictionary.waitAllTasksForTests(); - // Word - assertTrue(contextualDictionary.isInDictionary("a")); - assertTrue(contextualDictionary.isInDictionary("b")); - assertTrue(contextualDictionary.isInDictionary("c")); - assertTrue(contextualDictionary.isInDictionary("d")); - // Phrase - assertTrue(contextualDictionary.isInDictionary("a b c d")); - assertTrue(contextualDictionary.isInDictionary("b c d")); - assertTrue(contextualDictionary.isInDictionary("c d")); - assertFalse(contextualDictionary.isInDictionary("a b c")); - assertFalse(contextualDictionary.isInDictionary("abcd")); - // TODO: Add tests for probability. - // TODO: Add tests for n-grams. - } -} diff --git a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java b/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java deleted file mode 100644 index 548167f95..000000000 --- a/tests/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryTests.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2014 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.personalization; - -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.Random; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -import com.android.inputmethod.latin.BinaryDictionary; -import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.DictionaryFacilitator; -import com.android.inputmethod.latin.DictionaryFacilitatorProvider; -import com.android.inputmethod.latin.ExpandableBinaryDictionary; -import com.android.inputmethod.latin.RichInputMethodManager; -import com.android.inputmethod.latin.ExpandableBinaryDictionary.UpdateEntriesForInputEventsCallback; -import com.android.inputmethod.latin.common.CodePointUtils; -import com.android.inputmethod.latin.settings.SpacingAndPunctuations; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; -import android.view.inputmethod.InputMethodSubtype; - -/** - * Unit tests for personalization dictionary - */ -@LargeTest -public class PersonalizationDictionaryTests extends AndroidTestCase { - private static final String TAG = PersonalizationDictionaryTests.class.getSimpleName(); - - private static final Locale LOCALE_EN_US = new Locale("en", "US"); - private static final String DUMMY_PACKAGE_NAME = "test.package.name"; - private static final long TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS = 120; - - private DictionaryFacilitator getDictionaryFacilitator() { - final ArrayList<String> dictTypes = new ArrayList<>(); - dictTypes.add(Dictionary.TYPE_MAIN); - dictTypes.add(Dictionary.TYPE_PERSONALIZATION); - final DictionaryFacilitator dictionaryFacilitator = - DictionaryFacilitatorProvider.newDictionaryFacilitator(getContext()); - dictionaryFacilitator.resetDictionariesForTesting(getContext(), - new Locale[] { LOCALE_EN_US }, dictTypes, new HashMap<String, File>(), - Collections.<String, Map<String, String>>emptyMap(), null /* account */); - // Set subtypes. - RichInputMethodManager.init(getContext()); - final RichInputMethodManager richImm = RichInputMethodManager.getInstance(); - final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); - subtypes.add(richImm.findSubtypeByLocaleAndKeyboardLayoutSet( - LOCALE_EN_US.toString(), "qwerty")); - dictionaryFacilitator.updateEnabledSubtypes(subtypes); - return dictionaryFacilitator; - } - - public void testAddManyTokens() { - final DictionaryFacilitator dictionaryFacilitator = getDictionaryFacilitator(); - dictionaryFacilitator.clearPersonalizationDictionary(); - final int dataChunkCount = 100; - final int wordCountInOneChunk = 200; - final int uniqueWordCount = 100; - final Random random = new Random(System.currentTimeMillis()); - final int[] codePointSet = CodePointUtils.LATIN_ALPHABETS_LOWER; - final ArrayList<String> words = new ArrayList<>(); - for (int i = 0; i < uniqueWordCount; i++) { - words.add(CodePointUtils.generateWord(random, codePointSet)); - } - - final SpacingAndPunctuations spacingAndPunctuations = - new SpacingAndPunctuations(getContext().getResources()); - - final int timeStampInSeconds = (int)TimeUnit.MILLISECONDS.toSeconds( - System.currentTimeMillis()); - - for (int i = 0; i < dataChunkCount; i++) { - final ArrayList<String> tokens = new ArrayList<>(); - for (int j = 0; j < wordCountInOneChunk; j++) { - tokens.add(words.get(random.nextInt(words.size()))); - } - final PersonalizationDataChunk personalizationDataChunk = new PersonalizationDataChunk( - true /* inputByUser */, tokens, timeStampInSeconds, DUMMY_PACKAGE_NAME, - LOCALE_EN_US.getLanguage()); - final CountDownLatch countDownLatch = new CountDownLatch(1); - final UpdateEntriesForInputEventsCallback callback = - new UpdateEntriesForInputEventsCallback() { - @Override - public void onFinished() { - countDownLatch.countDown(); - } - }; - dictionaryFacilitator.addEntriesToPersonalizationDictionary(personalizationDataChunk, - spacingAndPunctuations, callback); - try { - countDownLatch.await(TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS, - TimeUnit.SECONDS); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted while waiting for finishing dictionary operations.", e); - } - } - dictionaryFacilitator.flushPersonalizationDictionary(); - try { - dictionaryFacilitator.waitForLoadingDictionariesForTesting( - TIMEOUT_TO_WAIT_DICTIONARY_OPERATIONS_IN_SECONDS, TimeUnit.SECONDS); - } catch (InterruptedException e) { - Log.e(TAG, "Interrupted while waiting for finishing dictionary operations.", e); - } - final String dictName = ExpandableBinaryDictionary.getDictName( - PersonalizationDictionary.NAME, LOCALE_EN_US, null /* dictFile */); - final File dictFile = ExpandableBinaryDictionary.getDictFile( - getContext(), dictName, null /* dictFile */); - - final BinaryDictionary binaryDictionary = new BinaryDictionary(dictFile.getAbsolutePath(), - 0 /* offset */, 0 /* size */, - true /* useFullEditDistance */, LOCALE_EN_US, Dictionary.TYPE_PERSONALIZATION, - true /* isUpdatable */); - assertTrue(binaryDictionary.isValidDictionary()); - } -} |