diff options
Diffstat (limited to 'java/src/com/android/inputmethod')
24 files changed, 476 insertions, 91 deletions
diff --git a/java/src/com/android/inputmethod/compat/BuildCompatUtils.java b/java/src/com/android/inputmethod/compat/BuildCompatUtils.java new file mode 100644 index 000000000..7d1717bd1 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/BuildCompatUtils.java @@ -0,0 +1,43 @@ +/* + * 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.compat; + +import android.os.Build; + +public final class BuildCompatUtils { + private BuildCompatUtils() { + // This utility class is not publicly instantiable. + } + + private static final boolean IS_RELEASE_BUILD = Build.VERSION.CODENAME.equals("REL"); + + /** + * The "effective" API version. + * {@link android.os.Build.VERSION#SDK_INT} if the platform is a release build. + * {@link android.os.Build.VERSION#SDK_INT} plus 1 if the platform is a development build. + */ + public static final int EFFECTIVE_SDK_INT = IS_RELEASE_BUILD + ? Build.VERSION.SDK_INT + : Build.VERSION.SDK_INT + 1; + + /** + * API version for L-release. + */ + // TODO: Substitute this constant reference with Build.VERSION_CODES.L* once the *next* version + // becomes available. + public static final int VERSION_CODES_LXX = 21; +} diff --git a/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java new file mode 100644 index 000000000..2cec14240 --- /dev/null +++ b/java/src/com/android/inputmethod/compat/CursorAnchorInfoCompatWrapper.java @@ -0,0 +1,135 @@ +/* + * 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.compat; + +import android.graphics.Matrix; +import android.graphics.RectF; + +import com.android.inputmethod.annotations.UsedForTesting; + +import java.lang.reflect.Method; + +@UsedForTesting +public final class CursorAnchorInfoCompatWrapper { + // Note that CursorAnchorInfo has been introduced in API level XX (Build.VERSION_CODE.LXX). + private static Class<?> getCursorAnchorInfoClass() { + try { + return Class.forName("android.view.inputmethod.CursorAnchorInfo"); + } catch (ClassNotFoundException e) { + return null; + } + } + private static final Class<?> CLASS; + private static final Method METHOD_GET_CHARACTER_RECT; + private static final Method METHOD_GET_CHARACTER_RECT_FLAGS; + private static final Method METHOD_GET_COMPOSING_TEXT; + private static final Method METHOD_GET_COMPOSING_TEXT_START; + private static final Method METHOD_GET_MATRIX; + static { + CLASS = getCursorAnchorInfoClass(); + METHOD_GET_CHARACTER_RECT = CompatUtils.getMethod(CLASS, "getCharacterRect", int.class); + METHOD_GET_CHARACTER_RECT_FLAGS = CompatUtils.getMethod(CLASS, "getCharacterRectFlags", + int.class); + METHOD_GET_COMPOSING_TEXT = CompatUtils.getMethod(CLASS, "getComposingText"); + METHOD_GET_COMPOSING_TEXT_START = CompatUtils.getMethod(CLASS, "getComposingTextStart"); + METHOD_GET_MATRIX = CompatUtils.getMethod(CLASS, "getMatrix"); + } + + @UsedForTesting + public static boolean isAvailable() { + return CLASS != null; + } + + public static final int CHARACTER_RECT_TYPE_MASK = 0x0f; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor did not specify any type of this + * character. Editor authors should not use this flag. + */ + public static final int CHARACTER_RECT_TYPE_UNSPECIFIED = 0; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely visible. + */ + public static final int CHARACTER_RECT_TYPE_FULLY_VISIBLE = 1; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: some area of the character is invisible. + */ + public static final int CHARACTER_RECT_TYPE_PARTIALLY_VISIBLE = 2; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the character is entirely invisible. + */ + public static final int CHARACTER_RECT_TYPE_INVISIBLE = 3; + + /** + * Type for {@link #CHARACTER_RECT_TYPE_MASK}: the editor gave up to calculate the rectangle + * for this character. Input method authors should ignore the returned rectangle. + */ + public static final int CHARACTER_RECT_TYPE_NOT_FEASIBLE = 4; + + private Object mInstance; + + private CursorAnchorInfoCompatWrapper(final Object instance) { + mInstance = instance; + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper fromObject(final Object instance) { + if (!isAvailable()) { + return new CursorAnchorInfoCompatWrapper(null); + } + return new CursorAnchorInfoCompatWrapper(instance); + } + + private static final class FakeHolder { + static CursorAnchorInfoCompatWrapper sInstance = new CursorAnchorInfoCompatWrapper(null); + } + + @UsedForTesting + public static CursorAnchorInfoCompatWrapper getFake() { + return FakeHolder.sInstance; + } + + public CharSequence getComposingText() { + return (CharSequence) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT); + } + + private static int COMPOSING_TEXT_START_DEFAULT = -1; + public int getComposingTextStart() { + if (mInstance == null || METHOD_GET_COMPOSING_TEXT_START == null) { + return COMPOSING_TEXT_START_DEFAULT; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_COMPOSING_TEXT_START); + } + + public Matrix getMatrix() { + return (Matrix) CompatUtils.invoke(mInstance, null, METHOD_GET_MATRIX); + } + + public RectF getCharacterRect(final int index) { + return (RectF) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT, index); + } + + public int getCharacterRectFlags(final int index) { + if (mInstance == null || METHOD_GET_CHARACTER_RECT_FLAGS == null) { + return CHARACTER_RECT_TYPE_UNSPECIFIED; + } + return (int) CompatUtils.invoke(mInstance, null, METHOD_GET_CHARACTER_RECT_FLAGS, index); + } +} diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java index f02f7885a..ef5b04747 100644 --- a/java/src/com/android/inputmethod/event/Event.java +++ b/java/src/com/android/inputmethod/event/Event.java @@ -257,6 +257,8 @@ public class Event { public boolean isConsumed() { return 0 != (FLAG_CONSUMED & mFlags); } + public boolean isGesture() { return EVENT_TYPE_GESTURE == mEventType; } + // Returns whether this is a fake key press from the suggestion strip. This happens with // punctuation signs selected from the suggestion strip. public boolean isSuggestionStripPress() { diff --git a/java/src/com/android/inputmethod/event/InputTransaction.java b/java/src/com/android/inputmethod/event/InputTransaction.java index b18bf5638..5bc9111de 100644 --- a/java/src/com/android/inputmethod/event/InputTransaction.java +++ b/java/src/com/android/inputmethod/event/InputTransaction.java @@ -33,7 +33,7 @@ public class InputTransaction { // Initial conditions public final SettingsValues mSettingsValues; - private final Event mEvent; + public final Event mEvent; public final long mTimestamp; public final int mSpaceState; public final int mShiftState; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index f35126750..140e76879 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; +import android.content.res.Configuration; import android.content.res.Resources; import android.preference.PreferenceManager; import android.util.Log; @@ -233,11 +234,21 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } private void setMainKeyboardFrame() { - mMainKeyboardFrame.setVisibility(View.VISIBLE); + mMainKeyboardFrame.setVisibility(hasHardwareKeyboard() ? View.GONE : View.VISIBLE); mEmojiPalettesView.setVisibility(View.GONE); mEmojiPalettesView.stopEmojiPalettes(); } + // TODO: Move this boolean to a member of {@link SettingsValues} and reset it + // at {@link LatinIME#onConfigurationChanged(Configuration)}. + public boolean hasHardwareKeyboard() { + // Copied from {@link InputMethodServce#onEvaluateInputViewShown()}. + final Configuration config = mLatinIME.getResources().getConfiguration(); + final boolean noHardwareKeyboard = config.keyboard == Configuration.KEYBOARD_NOKEYS + || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; + return !noHardwareKeyboard; + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setEmojiKeyboard() { @@ -249,6 +260,14 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { mEmojiPalettesView.setVisibility(View.VISIBLE); } + public void onToggleEmojiKeyboard() { + if (isShowingEmojiPalettes()) { + setAlphabetKeyboard(); + } else { + setEmojiKeyboard(); + } + } + // Implements {@link KeyboardState.SwitchActions}. @Override public void setSymbolsShiftedKeyboard() { diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java index 4c2e0dd1d..0cd606d19 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardTheme.java @@ -17,11 +17,11 @@ package com.android.inputmethod.keyboard; import android.content.SharedPreferences; -import android.os.Build; import android.os.Build.VERSION_CODES; import android.util.Log; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.latin.R; import java.util.Arrays; @@ -47,8 +47,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { VERSION_CODES.ICE_CREAM_SANDWICH), new KeyboardTheme(THEME_ID_LXX_LIGHT, R.style.KeyboardTheme_LXX_Light, // Default theme for LXX. - // TODO: Update this constant once the *next* version becomes available. - VERSION_CODES.CUR_DEVELOPMENT), + BuildCompatUtils.VERSION_CODES_LXX), new KeyboardTheme(THEME_ID_LXX_DARK, R.style.KeyboardTheme_LXX_Dark, VERSION_CODES.BASE), }; @@ -99,15 +98,6 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { return null; } - private static int getSdkVersion() { - final int sdkVersion = Build.VERSION.SDK_INT; - // TODO: Consider to remove this check once the *next* version becomes available. - if (sdkVersion > VERSION_CODES.KITKAT) { - return VERSION_CODES.CUR_DEVELOPMENT; - } - return sdkVersion; - } - @UsedForTesting static KeyboardTheme getDefaultKeyboardTheme(final SharedPreferences prefs, final int sdkVersion) { @@ -140,7 +130,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { public static void saveKeyboardThemeId(final String themeIdString, final SharedPreferences prefs) { - saveKeyboardThemeId(themeIdString, prefs, getSdkVersion()); + saveKeyboardThemeId(themeIdString, prefs, BuildCompatUtils.EFFECTIVE_SDK_INT); } @UsedForTesting @@ -159,7 +149,7 @@ public final class KeyboardTheme implements Comparable<KeyboardTheme> { } public static KeyboardTheme getKeyboardTheme(final SharedPreferences prefs) { - return getKeyboardTheme(prefs, getSdkVersion()); + return getKeyboardTheme(prefs, BuildCompatUtils.EFFECTIVE_SDK_INT); } @UsedForTesting diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java index 702efb3d7..1ef53a65d 100644 --- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java @@ -46,6 +46,7 @@ import com.android.inputmethod.keyboard.internal.GestureTrailsDrawingPreview; import com.android.inputmethod.keyboard.internal.KeyDrawParams; import com.android.inputmethod.keyboard.internal.KeyPreviewChoreographer; import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams; +import com.android.inputmethod.keyboard.internal.KeyPreviewView; import com.android.inputmethod.keyboard.internal.LanguageOnSpacebarHelper; import com.android.inputmethod.keyboard.internal.MoreKeySpec; import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper; @@ -764,6 +765,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack public void startDisplayLanguageOnSpacebar(final boolean subtypeChanged, final int languageOnSpacebarFormatType, final boolean hasMultipleEnabledIMEsOrSubtypes) { + if (subtypeChanged) { + KeyPreviewView.clearTextCache(); + } mLanguageOnSpacebarFormatType = languageOnSpacebarFormatType; mHasMultipleEnabledIMEsOrSubtypes = hasMultipleEnabledIMEsOrSubtypes; final ObjectAnimator animator = mLanguageOnSpacebarFadeoutAnimator; diff --git a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java index 512d4615d..0f9dc855b 100644 --- a/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java +++ b/java/src/com/android/inputmethod/keyboard/emoji/EmojiCategory.java @@ -24,6 +24,7 @@ import android.os.Build; import android.util.Log; import android.util.Pair; +import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.keyboard.Keyboard; import com.android.inputmethod.keyboard.KeyboardId; @@ -121,9 +122,7 @@ final class EmojiCategory { sCategoryTabIconAttr[i], 0); } addShownCategoryId(EmojiCategory.ID_RECENTS); - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 - || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KeyLimePie") - || android.os.Build.VERSION.CODENAME.equalsIgnoreCase("KitKat")) { + if (BuildCompatUtils.EFFECTIVE_SDK_INT >= Build.VERSION_CODES.KITKAT) { addShownCategoryId(EmojiCategory.ID_PEOPLE); addShownCategoryId(EmojiCategory.ID_OBJECTS); addShownCategoryId(EmojiCategory.ID_NATURE); diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java index 360faf829..24538605a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyPreviewView.java @@ -17,7 +17,10 @@ package com.android.inputmethod.keyboard.internal; import android.content.Context; +import android.graphics.Rect; import android.graphics.drawable.Drawable; +import android.text.TextPaint; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; import android.view.Gravity; @@ -26,6 +29,8 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.Key; import com.android.inputmethod.latin.R; +import java.util.HashSet; + /** * The pop up key preview view. */ @@ -34,6 +39,9 @@ public class KeyPreviewView extends TextView { public static final int POSITION_LEFT = 1; public static final int POSITION_RIGHT = 2; + private final Rect mBackgroundPadding = new Rect(); + private static final HashSet<String> sNoScaleXTextSet = new HashSet<>(); + public KeyPreviewView(final Context context, final AttributeSet attrs) { this(context, attrs, 0); } @@ -58,7 +66,48 @@ public class KeyPreviewView extends TextView { setTextSize(TypedValue.COMPLEX_UNIT_PX, key.selectPreviewTextSize(drawParams)); setTypeface(key.selectPreviewTypeface(drawParams)); // TODO Should take care of temporaryShiftLabel here. - setText(key.getPreviewLabel()); + setTextAndScaleX(key.getPreviewLabel()); + } + + private void setTextAndScaleX(final String text) { + setTextScaleX(1.0f); + setText(text); + if (sNoScaleXTextSet.contains(text)) { + return; + } + // TODO: Override {@link #setBackground(Drawable)} that is supported from API 16 and + // calculate maximum text width. + final Drawable background = getBackground(); + if (background == null) { + return; + } + background.getPadding(mBackgroundPadding); + final int maxWidth = background.getIntrinsicWidth() - mBackgroundPadding.left + - mBackgroundPadding.right; + final float width = getTextWidth(text, getPaint()); + if (width <= maxWidth) { + sNoScaleXTextSet.add(text); + return; + } + setTextScaleX(maxWidth / width); + } + + public static void clearTextCache() { + sNoScaleXTextSet.clear(); + } + + private static float getTextWidth(final String text, final TextPaint paint) { + if (TextUtils.isEmpty(text)) { + return 0.0f; + } + final int len = text.length(); + final float[] widths = new float[len]; + final int count = paint.getTextWidths(text, 0, len, widths); + float width = 0; + for (int i = 0; i < count; i++) { + width += widths[i]; + } + return width; } // Background state set diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java index 09550c4cb..e1f302c1e 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardIconsSet.java @@ -53,7 +53,8 @@ public final class KeyboardIconsSet { public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key"; public static final String NAME_ZWNJ_KEY = "zwnj_key"; public static final String NAME_ZWJ_KEY = "zwj_key"; - public static final String NAME_EMOJI_KEY = "emoji_key"; + public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key"; + public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key"; private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray(); @@ -81,7 +82,8 @@ public final class KeyboardIconsSet { NAME_LANGUAGE_SWITCH_KEY, R.styleable.Keyboard_iconLanguageSwitchKey, NAME_ZWNJ_KEY, R.styleable.Keyboard_iconZwnjKey, NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey, - NAME_EMOJI_KEY, R.styleable.Keyboard_iconEmojiKey, + NAME_EMOJI_ACTION_KEY, R.styleable.Keyboard_iconEmojiActionKey, + NAME_EMOJI_NORMAL_KEY, R.styleable.Keyboard_iconEmojiNormalKey, }; private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2; diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java index e6897bf1d..31bc549ca 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardTextsTable.java @@ -250,7 +250,7 @@ public final class KeyboardTextsTable { /* 164: 0 */ "morekeys_single_quote", /* 165: 0 */ "morekeys_double_quote", /* 166: 0 */ "morekeys_tablet_double_quote", - /* 167: 0 */ "keyspec_emoji_key", + /* 167: 0 */ "keyspec_emoji_action_key", }; private static final String EMPTY = ""; @@ -464,7 +464,7 @@ public final class KeyboardTextsTable { /* morekeys_single_quote */ "!fixedColumnOrder!5,!text/single_quotes,!text/single_angle_quotes", /* morekeys_double_quote */ "!fixedColumnOrder!5,!text/double_quotes,!text/double_angle_quotes", /* morekeys_tablet_double_quote */ "!fixedColumnOrder!6,!text/double_quotes,!text/single_quotes,!text/double_angle_quotes,!text/single_angle_quotes", - /* keyspec_emoji_key */ "!icon/emoji_key|!code/key_emoji", + /* keyspec_emoji_action_key */ "!icon/emoji_action_key|!code/key_emoji", }; /* Locale af: Afrikaans */ diff --git a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java index c11a220a4..22b91700c 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableBinaryDictionary.java @@ -647,7 +647,7 @@ abstract public class ExpandableBinaryDictionary extends Dictionary { @UsedForTesting public void waitAllTasksForTests() { final CountDownLatch countDownLatch = new CountDownLatch(1); - ExecutorUtils.getExecutor(mDictName).execute(new Runnable() { + asyncExecuteTaskWithWriteLock(new Runnable() { @Override public void run() { countDownLatch.countDown(); diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 2e3cd6b6f..71fd10e83 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -49,11 +49,13 @@ import android.view.ViewGroup.LayoutParams; 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 com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.compat.CursorAnchorInfoCompatWrapper; import com.android.inputmethod.compat.InputConnectionCompatUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; @@ -136,7 +138,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen new Runnable() { @Override public void run() { - mHandler.postUpdateSuggestionStrip(); + mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE); } }); private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */, @@ -145,6 +147,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // If it turns out we need several, it will get grown seamlessly. final SparseArray<HardwareEventDecoder> mHardwareEventDecoders = new SparseArray<>(1); + // TODO: Move these {@link View}s to {@link KeyboardSwitcher}. + private View mInputView; private View mExtractArea; private View mKeyPreviewBackingView; private SuggestionStripView mSuggestionStripView; @@ -153,6 +157,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @UsedForTesting final KeyboardSwitcher mKeyboardSwitcher; private final SubtypeSwitcher mSubtypeSwitcher; private final SubtypeState mSubtypeState = new SubtypeState(); + private final SpecialKeyDetector mSpecialKeyDetector; // Object for reacting to adding/removing a dictionary pack. private final BroadcastReceiver mDictionaryPackInstallReceiver = @@ -215,7 +220,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen case MSG_UPDATE_SUGGESTION_STRIP: cancelUpdateSuggestionStrip(); latinIme.mInputLogic.performUpdateSuggestionStripSync( - latinIme.mSettings.getCurrent()); + latinIme.mSettings.getCurrent(), msg.arg1 /* inputStyle */); break; case MSG_UPDATE_SHIFT_STATE: switcher.requestUpdatingShiftState(latinIme.getCurrentAutoCapsState(), @@ -265,8 +270,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } } - public void postUpdateSuggestionStrip() { - sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP), mDelayUpdateSuggestions); + public void postUpdateSuggestionStrip(final int inputStyle) { + sendMessageDelayed(obtainMessage(MSG_UPDATE_SUGGESTION_STRIP, inputStyle, + 0 /* ignored */), mDelayUpdateSuggestions); } public void postReopenDictionaries() { @@ -419,9 +425,12 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen latinIme.getCurrentInputConnection(), true /* enableMonitor */); } if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) { - InputConnectionCompatUtils.requestCursorAnchorInfo( - latinIme.getCurrentInputConnection(), true /* enableMonitor */, - true /* requestImmediateCallback */); + // AcceptTypedWord feature relies on CursorAnchorInfo. + if (latinIme.mSettings.getCurrent().mShouldShowUiToAcceptTypedWord) { + InputConnectionCompatUtils.requestCursorAnchorInfo( + latinIme.getCurrentInputConnection(), true /* enableMonitor */, + true /* requestImmediateCallback */); + } } } } @@ -514,6 +523,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSettings = Settings.getInstance(); mSubtypeSwitcher = SubtypeSwitcher.getInstance(); mKeyboardSwitcher = KeyboardSwitcher.getInstance(); + mSpecialKeyDetector = new SpecialKeyDetector(this); mIsHardwareAcceleratedDrawingEnabled = InputMethodServiceCompatUtils.enableHardwareAcceleration(this); Log.i(TAG, "Hardware accelerated drawing: " + mIsHardwareAcceleratedDrawingEnabled); @@ -709,6 +719,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen @Override public void setInputView(final View view) { super.setInputView(view); + mInputView = view; mExtractArea = getWindow().getWindow().getDecorView() .findViewById(android.R.id.extractArea); mKeyPreviewBackingView = view.findViewById(R.id.key_preview_backing); @@ -967,6 +978,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen super.onUpdateCursor(rect); } + // We cannot mark this method as @Override until new SDK becomes publicly available. + // @Override + public void onUpdateCursorAnchorInfo(final CursorAnchorInfo info) { + if (ProductionFlags.ENABLE_CURSOR_ANCHOR_INFO_CALLBACK) { + final CursorAnchorInfoCompatWrapper wrapper = + CursorAnchorInfoCompatWrapper.fromObject(info); + // TODO: Implement here + } + } + /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides @@ -1040,7 +1061,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen applicationSpecifiedCompletions); final SuggestedWords suggestedWords = new SuggestedWords(applicationSuggestedWords, null /* rawSuggestions */, false /* typedWordValid */, false /* willAutoCorrect */, - false /* isObsoleteSuggestions */, false /* isPrediction */); + false /* isObsoleteSuggestions */, false /* isPrediction */, + SuggestedWords.INPUT_STYLE_APPLICATION_SPECIFIED /* inputStyle */); // When in fullscreen mode, show completions generated by the application forcibly setSuggestedWords(suggestedWords); } @@ -1079,6 +1101,14 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (visibleKeyboardView == null || !hasSuggestionStripView()) { return; } + final boolean hasHardwareKeyboard = mKeyboardSwitcher.hasHardwareKeyboard(); + if (hasHardwareKeyboard && visibleKeyboardView.getVisibility() == View.GONE) { + // If there is a hardware keyboard and a visible software keyboard view has been hidden, + // no visual element will be shown on the screen. + outInsets.touchableInsets = mInputView.getHeight(); + outInsets.visibleTopInsets = mInputView.getHeight(); + return; + } final int adjustedBackingHeight = getAdjustedBackingViewHeight(); final boolean backingGone = (mKeyPreviewBackingView.getVisibility() == View.GONE); final int backingHeight = backingGone ? 0 : adjustedBackingHeight; @@ -1111,7 +1141,17 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override + public boolean onEvaluateInputViewShown() { + // Always show {@link InputView}. + return true; + } + + @Override public boolean onEvaluateFullscreenMode() { + if (mKeyboardSwitcher.hasHardwareKeyboard()) { + // If there is a hardware keyboard, disable full screen mode. + return false; + } // Reread resource value here, because this method is called by the framework as needed. final boolean isFullscreenModeAllowed = Settings.readUseFullscreenMode(getResources()); if (super.onEvaluateFullscreenMode() && isFullscreenModeAllowed) { @@ -1413,7 +1453,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // TODO[IL]: Move this out of LatinIME. - public void getSuggestedWords(final int sessionId, final int sequenceNumber, + public void getSuggestedWords(final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); if (keyboard == null) { @@ -1421,7 +1461,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return; } mInputLogic.getSuggestedWords(mSettings.getCurrent(), keyboard.getProximityInfo(), - mKeyboardSwitcher.getKeyboardShiftMode(), sessionId, sequenceNumber, callback); + mKeyboardSwitcher.getKeyboardShiftMode(), inputStyle, sequenceNumber, callback); } @Override @@ -1505,7 +1545,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen default: // SHIFT_NO_UPDATE } if (inputTransaction.requiresUpdateSuggestions()) { - mHandler.postUpdateSuggestionStrip(); + final int inputStyle; + if (inputTransaction.mEvent.isSuggestionStripPress()) { + // Suggestion strip press: no input. + inputStyle = SuggestedWords.INPUT_STYLE_NONE; + } else if (inputTransaction.mEvent.isGesture()) { + inputStyle = SuggestedWords.INPUT_STYLE_TAIL_BATCH; + } else { + inputStyle = SuggestedWords.INPUT_STYLE_TYPING; + } + mHandler.postUpdateSuggestionStrip(inputStyle); } if (inputTransaction.didAffectContents()) { mSubtypeState.setCurrentSubtypeHasBeenUsed(); @@ -1568,6 +1617,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen // Hooks for hardware keyboard @Override public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyDown(keyEvent); if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { return super.onKeyDown(keyCode, keyEvent); } @@ -1587,12 +1637,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } @Override - public boolean onKeyUp(final int keyCode, final KeyEvent event) { - final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode(); + public boolean onKeyUp(final int keyCode, final KeyEvent keyEvent) { + mSpecialKeyDetector.onKeyUp(keyEvent); + if (!ProductionFlags.IS_HARDWARE_KEYBOARD_SUPPORTED) { + return super.onKeyUp(keyCode, keyEvent); + } + final long keyIdentifier = keyEvent.getDeviceId() << 32 + keyEvent.getKeyCode(); if (mInputLogic.mCurrentlyPressedHardwareKeys.remove(keyIdentifier)) { return true; } - return super.onKeyUp(keyCode, event); + return super.onKeyUp(keyCode, keyEvent); } // onKeyDown and onKeyUp are the main events we are interested in. There are two more events diff --git a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java index 0fba37c8a..6b0205c0f 100644 --- a/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java +++ b/java/src/com/android/inputmethod/latin/PunctuationSuggestions.java @@ -35,7 +35,8 @@ public final class PunctuationSuggestions extends SuggestedWords { false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, false /* isObsoleteSuggestions */, - false /* isPrediction */); + false /* isPrediction */, + INPUT_STYLE_NONE /* inputStyle */); } /** diff --git a/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java new file mode 100644 index 000000000..27b2f5012 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/SpecialKeyDetector.java @@ -0,0 +1,43 @@ +/* + * 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 android.content.Context; +import android.view.KeyEvent; + +final class SpecialKeyDetector { + /** + * Special physical key detector + * @param context a context of this detector. + */ + public SpecialKeyDetector(final Context context) { + } + + /** + * Record a down key event. + * @param keyEvent a down key event. + */ + public void onKeyDown(final KeyEvent keyEvent) { + } + + /** + * Record an up key event. + * @param keyEvent an up key event. + */ + public void onKeyUp(final KeyEvent keyEvent) { + } +} diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index b8b6d6471..ab852f8dd 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -40,13 +40,8 @@ public final class Suggest { // Session id for // {@link #getSuggestedWords(WordComposer,String,ProximityInfo,boolean,int)}. // We are sharing the same ID between typing and gesture to save RAM footprint. - public static final int SESSION_TYPING = 0; - public static final int SESSION_GESTURE = 0; - - // TODO: rename this to CORRECTION_OFF - public static final int CORRECTION_NONE = 0; - // TODO: rename this to CORRECTION_ON - public static final int CORRECTION_FULL = 1; + public static final int SESSION_ID_TYPING = 0; + public static final int SESSION_ID_GESTURE = 0; // Close to -2**31 private static final int SUPPRESS_SUGGEST_THRESHOLD = -2000000000; @@ -75,14 +70,15 @@ public final class Suggest { public void getSuggestedWords(final WordComposer wordComposer, final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, final SettingsValuesForSuggestion settingsValuesForSuggestion, - final boolean isCorrectionEnabled, final int sessionId, final int sequenceNumber, + final boolean isCorrectionEnabled, final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { if (wordComposer.isBatchMode()) { getSuggestedWordsForBatchInput(wordComposer, prevWordsInfo, proximityInfo, - settingsValuesForSuggestion, sessionId, sequenceNumber, callback); + settingsValuesForSuggestion, inputStyle, sequenceNumber, callback); } else { - getSuggestedWordsForTypingInput(wordComposer, prevWordsInfo, proximityInfo, - settingsValuesForSuggestion, isCorrectionEnabled, sequenceNumber, callback); + getSuggestedWordsForNonBatchInput(wordComposer, prevWordsInfo, proximityInfo, + settingsValuesForSuggestion, inputStyle, isCorrectionEnabled, + sequenceNumber, callback); } } @@ -120,11 +116,11 @@ public final class Suggest { return firstSuggestedWordInfo.mWord; } - // Retrieves suggestions for the typing input + // Retrieves suggestions for non-batch input (typing, recorrection, predictions...) // and calls the callback function with the suggestions. - private void getSuggestedWordsForTypingInput(final WordComposer wordComposer, + private void getSuggestedWordsForNonBatchInput(final WordComposer wordComposer, final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, - final SettingsValuesForSuggestion settingsValuesForSuggestion, + final SettingsValuesForSuggestion settingsValuesForSuggestion, final int inputStyle, final boolean isCorrectionEnabled, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final String typedWord = wordComposer.getTypedWord(); @@ -135,7 +131,7 @@ public final class Suggest { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion, - SESSION_TYPING); + SESSION_ID_TYPING); final ArrayList<SuggestedWordInfo> suggestionsContainer = getTransformedSuggestedWordInfoList(wordComposer, suggestionResults, trailingSingleQuotesCount); @@ -197,7 +193,8 @@ public final class Suggest { // rename the attribute or change the value. !resultsArePredictions && !allowsToBeAutoCorrected /* typedWordValid */, hasAutoCorrection /* willAutoCorrect */, - false /* isObsoleteSuggestions */, resultsArePredictions, sequenceNumber)); + false /* isObsoleteSuggestions */, resultsArePredictions, + inputStyle, sequenceNumber)); } // Retrieves suggestions for the batch input @@ -205,10 +202,11 @@ public final class Suggest { private void getSuggestedWordsForBatchInput(final WordComposer wordComposer, final PrevWordsInfo prevWordsInfo, final ProximityInfo proximityInfo, final SettingsValuesForSuggestion settingsValuesForSuggestion, - final int sessionId, final int sequenceNumber, + final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { final SuggestionResults suggestionResults = mDictionaryFacilitator.getSuggestionResults( - wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion, sessionId); + wordComposer, prevWordsInfo, proximityInfo, settingsValuesForSuggestion, + SESSION_ID_GESTURE); final ArrayList<SuggestedWordInfo> suggestionsContainer = new ArrayList<>(suggestionResults); final int suggestionsCount = suggestionsContainer.size(); @@ -246,7 +244,8 @@ public final class Suggest { true /* typedWordValid */, false /* willAutoCorrect */, false /* isObsoleteSuggestions */, - false /* isPrediction */, sequenceNumber)); + false /* isPrediction */, + inputStyle, sequenceNumber)); } private static ArrayList<SuggestedWordInfo> getSuggestionsInfoListWithDebugInfo( diff --git a/java/src/com/android/inputmethod/latin/SuggestedWords.java b/java/src/com/android/inputmethod/latin/SuggestedWords.java index 5231cc893..d7693af41 100644 --- a/java/src/com/android/inputmethod/latin/SuggestedWords.java +++ b/java/src/com/android/inputmethod/latin/SuggestedWords.java @@ -31,12 +31,20 @@ public class SuggestedWords { public static final int INDEX_OF_AUTO_CORRECTION = 1; public static final int NOT_A_SEQUENCE_NUMBER = -1; + public static final int INPUT_STYLE_NONE = 0; + public static final int INPUT_STYLE_TYPING = 1; + public static final int INPUT_STYLE_UPDATE_BATCH = 2; + public static final int INPUT_STYLE_TAIL_BATCH = 3; + public static final int INPUT_STYLE_APPLICATION_SPECIFIED = 4; + public static final int INPUT_STYLE_RECORRECTION = 5; + // The maximum number of suggestions available. public static final int MAX_SUGGESTIONS = 18; private static final ArrayList<SuggestedWordInfo> EMPTY_WORD_INFO_LIST = new ArrayList<>(0); public static final SuggestedWords EMPTY = new SuggestedWords( - EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false); + EMPTY_WORD_INFO_LIST, null /* rawSuggestions */, false, false, false, false, + INPUT_STYLE_NONE); public final String mTypedWord; public final boolean mTypedWordValid; @@ -46,6 +54,9 @@ public class SuggestedWords { public final boolean mWillAutoCorrect; public final boolean mIsObsoleteSuggestions; public final boolean mIsPrediction; + // How the input for these suggested words was done by the user. Must be one of the + // INPUT_STYLE_* constants above. + public final int mInputStyle; public final int mSequenceNumber; // Sequence number for auto-commit. protected final ArrayList<SuggestedWordInfo> mSuggestedWordInfoList; public final ArrayList<SuggestedWordInfo> mRawSuggestions; @@ -55,9 +66,10 @@ public class SuggestedWords { final boolean typedWordValid, final boolean willAutoCorrect, final boolean isObsoleteSuggestions, - final boolean isPrediction) { + final boolean isPrediction, + final int inputStyle) { this(suggestedWordInfoList, rawSuggestions, typedWordValid, willAutoCorrect, - isObsoleteSuggestions, isPrediction, NOT_A_SEQUENCE_NUMBER); + isObsoleteSuggestions, isPrediction, inputStyle, NOT_A_SEQUENCE_NUMBER); } public SuggestedWords(final ArrayList<SuggestedWordInfo> suggestedWordInfoList, @@ -66,11 +78,12 @@ public class SuggestedWords { final boolean willAutoCorrect, final boolean isObsoleteSuggestions, final boolean isPrediction, + final int inputStyle, final int sequenceNumber) { this(suggestedWordInfoList, rawSuggestions, (suggestedWordInfoList.isEmpty() || isPrediction) ? null : suggestedWordInfoList.get(INDEX_OF_TYPED_WORD).mWord, - typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction, + typedWordValid, willAutoCorrect, isObsoleteSuggestions, isPrediction, inputStyle, sequenceNumber); } @@ -81,6 +94,7 @@ public class SuggestedWords { final boolean willAutoCorrect, final boolean isObsoleteSuggestions, final boolean isPrediction, + final int inputStyle, final int sequenceNumber) { mSuggestedWordInfoList = suggestedWordInfoList; mRawSuggestions = rawSuggestions; @@ -88,6 +102,7 @@ public class SuggestedWords { mWillAutoCorrect = willAutoCorrect; mIsObsoleteSuggestions = isObsoleteSuggestions; mIsPrediction = isPrediction; + mInputStyle = inputStyle; mSequenceNumber = sequenceNumber; mTypedWord = typedWord; } @@ -367,7 +382,7 @@ public class SuggestedWords { // SuggestedWords is an immutable object, as much as possible. We must not just remove // words from the member ArrayList as some other parties may expect the object to never change. - public SuggestedWords getSuggestedWordsExcludingTypedWord() { + public SuggestedWords getSuggestedWordsExcludingTypedWord(final int inputStyle) { final ArrayList<SuggestedWordInfo> newSuggestions = new ArrayList<>(); String typedWord = null; for (int i = 0; i < mSuggestedWordInfoList.size(); ++i) { @@ -383,7 +398,7 @@ public class SuggestedWords { // no auto-correction should take place hence willAutoCorrect = false. return new SuggestedWords(newSuggestions, null /* rawSuggestions */, typedWord, true /* typedWordValid */, false /* willAutoCorrect */, mIsObsoleteSuggestions, - mIsPrediction, NOT_A_SEQUENCE_NUMBER); + mIsPrediction, inputStyle, NOT_A_SEQUENCE_NUMBER); } // Creates a new SuggestedWordInfo from the currently suggested words that removes all but the @@ -402,6 +417,7 @@ public class SuggestedWords { SuggestedWordInfo.NOT_A_CONFIDENCE)); } return new SuggestedWords(newSuggestions, null /* rawSuggestions */, mTypedWordValid, - mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction); + mWillAutoCorrect, mIsObsoleteSuggestions, mIsPrediction, + INPUT_STYLE_TAIL_BATCH); } } diff --git a/java/src/com/android/inputmethod/latin/define/ProductionFlags.java b/java/src/com/android/inputmethod/latin/define/ProductionFlags.java index d385cf840..461c226a1 100644 --- a/java/src/com/android/inputmethod/latin/define/ProductionFlags.java +++ b/java/src/com/android/inputmethod/latin/define/ProductionFlags.java @@ -29,7 +29,7 @@ public final class ProductionFlags { * and prior. In general, this callback provides more detailed positional information, * even though an explicit support is required by the editor. */ - public static final boolean ENABLE_CURSOR_ANCHOR_INFO_CALLBACK = false; + public static final boolean ENABLE_CURSOR_ANCHOR_INFO_CALLBACK = true; /** * When true, enable {@link InputMethodService#onUpdateCursor} callback via diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java index 418866ae1..348bae63a 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java @@ -216,7 +216,7 @@ public final class InputLogic { } else { resetComposingState(true /* alsoResetLastComposedWord */); } - handler.postUpdateSuggestionStrip(); + handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_TYPING); final String text = performSpecificTldProcessingOnTextInput(rawText); if (SpaceState.PHANTOM == mSpaceState) { promotePhantomSpace(settingsValues); @@ -288,9 +288,6 @@ public final class InputLogic { return inputTransaction; } - // We need to log before we commit, because the word composer will store away the user - // typed word. - final String replacedWord = mWordComposer.getTypedWord(); commitChosenWord(settingsValues, suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK, LastComposedWord.NOT_A_SEPARATOR); mConnection.endBatchEdit(); @@ -311,7 +308,8 @@ public final class InputLogic { mSuggestionStripViewAccessor.showAddToDictionaryHint(suggestion); } else { // If we're not showing the "Touch again to save", then update the suggestion strip. - handler.postUpdateSuggestionStrip(); + // That's going to be predictions (or punctuation suggestions), so INPUT_STYLE_NONE. + handler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_NONE); } return inputTransaction; } @@ -1299,7 +1297,8 @@ public final class InputLogic { prevWordsInfo, timeStampInSeconds, settingsValues.mBlockPotentiallyOffensive); } - public void performUpdateSuggestionStripSync(final SettingsValues settingsValues) { + public void performUpdateSuggestionStripSync(final SettingsValues settingsValues, + final int inputStyle) { // Check if we have a suggestion engine attached. if (!settingsValues.needsToLookupSuggestions()) { if (mWordComposer.isComposingWord()) { @@ -1317,8 +1316,8 @@ public final class InputLogic { } final AsyncResultHolder<SuggestedWords> holder = new AsyncResultHolder<>(); - mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING, - SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { + mInputLogicHandler.getSuggestedWords(inputStyle, SuggestedWords.NOT_A_SEQUENCE_NUMBER, + new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(final SuggestedWords suggestedWords) { final String typedWord = mWordComposer.getTypedWord(); @@ -1379,7 +1378,7 @@ public final class InputLogic { if (!mConnection.isCursorTouchingWord(settingsValues.mSpacingAndPunctuations)) { // Show predictions. mWordComposer.setCapitalizedModeAtStartComposingTime(WordComposer.CAPS_MODE_OFF); - mLatinIME.mHandler.postUpdateSuggestionStrip(); + mLatinIME.mHandler.postUpdateSuggestionStrip(SuggestedWords.INPUT_STYLE_RECORRECTION); return; } final TextRange range = mConnection.getWordRangeAtCursor( @@ -1444,7 +1443,7 @@ public final class InputLogic { // If there weren't any suggestion spans on this word, suggestions#size() will be 1 // if shouldIncludeResumedWordInSuggestions is true, 0 otherwise. In this case, we // have no useful suggestions, so we will try to compute some for it instead. - mInputLogicHandler.getSuggestedWords(Suggest.SESSION_TYPING, + mInputLogicHandler.getSuggestedWords(Suggest.SESSION_ID_TYPING, SuggestedWords.NOT_A_SEQUENCE_NUMBER, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords( @@ -1457,7 +1456,8 @@ public final class InputLogic { // case. The #getSuggestedWordsExcludingTypedWord() method sets // willAutoCorrect to false. suggestedWords = suggestedWordsIncludingTypedWord - .getSuggestedWordsExcludingTypedWord(); + .getSuggestedWordsExcludingTypedWord(SuggestedWords + .INPUT_STYLE_RECORRECTION); } else { // No saved suggestions, and we were unable to compute any good one // either. Rather than displaying an empty suggestion strip, we'll @@ -1477,6 +1477,7 @@ public final class InputLogic { null /* rawSuggestions */, typedWord, false /* typedWordValid */, false /* willAutoCorrect */, false /* isObsoleteSuggestions */, false /* isPrediction */, + SuggestedWords.INPUT_STYLE_RECORRECTION, SuggestedWords.NOT_A_SEQUENCE_NUMBER); mIsAutoCorrectionIndicatorOn = false; mLatinIME.mHandler.showSuggestionStrip(suggestedWords); @@ -1773,7 +1774,8 @@ public final class InputLogic { SuggestedWords.getTypedWordAndPreviousSuggestions(typedWord, oldSuggestedWords); return new SuggestedWords(typedWordAndPreviousSuggestions, null /* rawSuggestions */, false /* typedWordValid */, false /* hasAutoCorrectionCandidate */, - true /* isObsoleteSuggestions */, false /* isPrediction */); + true /* isObsoleteSuggestions */, false /* isPrediction */, + oldSuggestedWords.mInputStyle); } /** @@ -1956,7 +1958,15 @@ public final class InputLogic { // Complete any pending suggestions query first if (handler.hasPendingUpdateSuggestions()) { handler.cancelUpdateSuggestionStrip(); - performUpdateSuggestionStripSync(settingsValues); + // To know the input style here, we should retrieve the in-flight "update suggestions" + // message and read its arg1 member here. However, the Handler class does not let + // us retrieve this message, so we can't do that. But in fact, we notice that + // we only ever come here when the input style was typing. In the case of batch + // input, we update the suggestions synchronously when the tail batch comes. Likewise + // for application-specified completions. As for recorrections, we never auto-correct, + // so we don't come here either. Hence, the input style is necessarily + // INPUT_STYLE_TYPING. + performUpdateSuggestionStripSync(settingsValues, SuggestedWords.INPUT_STYLE_TYPING); } final String typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); final String typedWord = mWordComposer.getTypedWord(); @@ -2052,7 +2062,7 @@ public final class InputLogic { } public void getSuggestedWords(final SettingsValues settingsValues, - final ProximityInfo proximityInfo, final int keyboardShiftMode, final int sessionId, + final ProximityInfo proximityInfo, final int keyboardShiftMode, final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { mWordComposer.adviseCapitalizedModeBeforeFetchingSuggestions( getActualCapsMode(settingsValues, keyboardShiftMode)); @@ -2068,6 +2078,6 @@ public final class InputLogic { settingsValues.mPhraseGestureEnabled, settingsValues.mAdditionalFeaturesSettingValues), settingsValues.mAutoCorrectionEnabledPerUserSettings, - sessionId, sequenceNumber, callback); + inputStyle, sequenceNumber, callback); } } diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java index 9dbe2c38b..c6f83d0b9 100644 --- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java +++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogicHandler.java @@ -96,7 +96,7 @@ class InputLogicHandler implements Handler.Callback { public boolean handleMessage(final Message msg) { switch (msg.what) { case MSG_GET_SUGGESTED_WORDS: - mLatinIME.getSuggestedWords(msg.arg1 /* sessionId */, + mLatinIME.getSuggestedWords(msg.arg1 /* inputStyle */, msg.arg2 /* sequenceNumber */, (OnGetSuggestedWordsCallback) msg.obj); break; } @@ -134,7 +134,8 @@ class InputLogicHandler implements Handler.Callback { return; } mInputLogic.mWordComposer.setBatchInputPointers(batchPointers); - getSuggestedWords(Suggest.SESSION_GESTURE, sequenceNumber, + getSuggestedWords(isTailBatchInput ? SuggestedWords.INPUT_STYLE_TAIL_BATCH + : SuggestedWords.INPUT_STYLE_UPDATE_BATCH, sequenceNumber, new OnGetSuggestedWordsCallback() { @Override public void onGetSuggestedWords(SuggestedWords suggestedWords) { @@ -205,9 +206,9 @@ class InputLogicHandler implements Handler.Callback { updateBatchInput(batchPointers, sequenceNumber, true /* isTailBatchInput */); } - public void getSuggestedWords(final int sessionId, final int sequenceNumber, + public void getSuggestedWords(final int inputStyle, final int sequenceNumber, final OnGetSuggestedWordsCallback callback) { mNonUIThreadHandler.obtainMessage( - MSG_GET_SUGGESTED_WORDS, sessionId, sequenceNumber, callback).sendToTarget(); + MSG_GET_SUGGESTED_WORDS, inputStyle, sequenceNumber, callback).sendToTarget(); } } diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java index dce11b434..63d848e2d 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettings.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettings.java @@ -19,6 +19,10 @@ package com.android.inputmethod.latin.settings; public final class DebugSettings { public static final String PREF_DEBUG_MODE = "debug_mode"; public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch"; + public static final String PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY = + "force_physical_keyboard_special_key"; + public static final String PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD = + "pref_show_ui_to_accept_typed_word"; public static final String PREF_KEY_PREVIEW_SHOW_UP_START_SCALE = "pref_key_preview_show_up_start_scale"; public static final String PREF_KEY_PREVIEW_DISMISS_END_SCALE = diff --git a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java index 4e41d52a3..dc2f88aa8 100644 --- a/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java +++ b/java/src/com/android/inputmethod/latin/settings/DebugSettingsFragment.java @@ -56,6 +56,10 @@ public final class DebugSettingsFragment extends SubScreenFragment super.onCreate(icicle); addPreferencesFromResource(R.xml.prefs_screen_debug); + if (!Settings.HAS_UI_TO_ACCEPT_TYPED_WORD) { + removePreference(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD); + } + mReadExternalDictionaryPref = findPreference(PREF_READ_EXTERNAL_DICTIONARY); if (mReadExternalDictionaryPref != null) { mReadExternalDictionaryPref.setOnPreferenceClickListener(this); @@ -133,7 +137,8 @@ public final class DebugSettingsFragment extends SubScreenFragment mServiceNeedsRestart = true; return; } - if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH)) { + if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH) + || key.equals(DebugSettings.PREF_FORCE_PHYSICAL_KEYBOARD_SPECIAL_KEY)) { mServiceNeedsRestart = true; return; } diff --git a/java/src/com/android/inputmethod/latin/settings/Settings.java b/java/src/com/android/inputmethod/latin/settings/Settings.java index 90174e490..9d3c27bbe 100644 --- a/java/src/com/android/inputmethod/latin/settings/Settings.java +++ b/java/src/com/android/inputmethod/latin/settings/Settings.java @@ -24,6 +24,7 @@ import android.os.Build; import android.preference.PreferenceManager; import android.util.Log; +import com.android.inputmethod.compat.BuildCompatUtils; import com.android.inputmethod.latin.AudioAndHapticFeedbackManager; import com.android.inputmethod.latin.InputAttributes; import com.android.inputmethod.latin.R; @@ -68,9 +69,9 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_BLOCK_POTENTIALLY_OFFENSIVE = "pref_key_block_potentially_offensive"; public static final boolean ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS = - (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) - || (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT - && Build.VERSION.CODENAME.equals("REL")); + BuildCompatUtils.EFFECTIVE_SDK_INT <= Build.VERSION_CODES.KITKAT; + public static final boolean HAS_UI_TO_ACCEPT_TYPED_WORD = + BuildCompatUtils.EFFECTIVE_SDK_INT >= BuildCompatUtils.VERSION_CODES_LXX; public static final String PREF_SHOW_LANGUAGE_SWITCH_KEY = "pref_show_language_switch_key"; public static final String PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST = diff --git a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java index 39e834f84..c12474b3d 100644 --- a/java/src/com/android/inputmethod/latin/settings/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/settings/SettingsValues.java @@ -40,7 +40,8 @@ import java.util.Locale; * When you call the constructor of this class, you may want to change the current system locale by * using {@link com.android.inputmethod.latin.utils.RunInLocale}. */ -public final class SettingsValues { +// Non-final for testing via mock library. +public class SettingsValues { private static final String TAG = SettingsValues.class.getSimpleName(); // "floatMaxValue" and "floatNegativeInfinity" are special marker strings for // Float.NEGATIVE_INFINITE and Float.MAX_VALUE. Currently used for auto-correction settings. @@ -75,6 +76,7 @@ public final class SettingsValues { public final int mKeyLongpressTimeout; public final Locale mLocale; public final boolean mEnableMetricsLogging; + public final boolean mShouldShowUiToAcceptTypedWord; // From the input box public final InputAttributes mInputAttributes; @@ -142,6 +144,8 @@ public final class SettingsValues { mBigramPredictionEnabled = readBigramPredictionEnabled(prefs, res); mDoubleSpacePeriodTimeout = res.getInteger(R.integer.config_double_space_period_timeout); mEnableMetricsLogging = prefs.getBoolean(Settings.PREF_ENABLE_METRICS_LOGGING, true); + mShouldShowUiToAcceptTypedWord = Settings.HAS_UI_TO_ACCEPT_TYPED_WORD + && prefs.getBoolean(DebugSettings.PREF_SHOW_UI_TO_ACCEPT_TYPED_WORD, true); // Compute other readable settings mKeyLongpressTimeout = Settings.readKeyLongpressTimeout(prefs, res); mKeypressVibrationDuration = Settings.readKeypressVibrationDuration(prefs, res); @@ -186,6 +190,10 @@ public final class SettingsValues { } } + public boolean isMetricsLoggingEnabled() { + return mEnableMetricsLogging; + } + public boolean isApplicationSpecifiedCompletionsOn() { return mInputAttributes.mApplicationSpecifiedCompletionOn; } |