diff options
Diffstat (limited to 'java/src/com')
17 files changed, 325 insertions, 269 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java index cacb8a324..ae5e4e860 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java @@ -244,9 +244,10 @@ public class KeyboardSet { // TODO: Use InputMethodSubtype object as argument. public Builder setSubtype(Locale inputLocale, boolean asciiCapable, boolean touchPositionCorrectionEnabled) { + final boolean deprecatedForceAscii = Utils.inPrivateImeOptions( + mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(mParams.mImeOptions) - || Utils.inPrivateImeOptions( - mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, mEditorInfo); + || deprecatedForceAscii; mParams.mLocale = (forceAscii && !asciiCapable) ? Locale.US : inputLocale; mParams.mTouchPositionCorrectionEnabled = touchPositionCorrectionEnabled; return this; @@ -256,10 +257,11 @@ public class KeyboardSet { boolean voiceKeyOnMain) { mParams.mSettingsKeyEnabled = settingsKeyEnabled; @SuppressWarnings("deprecation") + final boolean deprecatedNoMicrophone = Utils.inPrivateImeOptions( + null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); final boolean noMicrophone = Utils.inPrivateImeOptions( mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, mEditorInfo) - || Utils.inPrivateImeOptions( - null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, mEditorInfo); + || deprecatedNoMicrophone; mParams.mVoiceKeyEnabled = voiceKeyEnabled && !noMicrophone; mParams.mVoiceKeyOnMain = voiceKeyOnMain; return this; diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java index 1398bae2a..5a59cc1c7 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java @@ -240,6 +240,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, private static final int ALPHABET_MANUAL_SHIFTED = 1; private static final int ALPHABET_AUTOMATIC_SHIFTED = 2; private static final int ALPHABET_SHIFT_LOCKED = 3; + private static final int ALPHABET_SHIFT_LOCK_SHIFTED = 4; // TODO: Remove this method. private void updateAlphabetKeyboardShiftState(int shiftMode) { @@ -260,6 +261,10 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, case ALPHABET_SHIFT_LOCKED: keyboard.setShiftLocked(true); break; + case ALPHABET_SHIFT_LOCK_SHIFTED: + keyboard.setShiftLocked(true); + keyboard.setShifted(true); + break; } mKeyboardView.invalidateAllKeys(); if (shiftMode != ALPHABET_SHIFT_LOCKED) { @@ -300,6 +305,13 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions, // Implements {@link KeyboardState.SwitchActions}. @Override + public void setAlphabetShiftLockShiftedKeyboard() { + setKeyboard(mKeyboardSet.getMainKeyboard()); + updateAlphabetKeyboardShiftState(ALPHABET_SHIFT_LOCK_SHIFTED); + } + + // Implements {@link KeyboardState.SwitchActions}. + @Override public void setSymbolsKeyboard() { setKeyboard(mKeyboardSet.getSymbolsKeyboard()); } diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java index afcf51059..6f4ef2580 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java @@ -17,7 +17,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -39,7 +38,6 @@ import android.widget.RelativeLayout; import android.widget.TextView; import com.android.inputmethod.compat.FrameLayoutCompatUtils; -import com.android.inputmethod.keyboard.internal.KeyboardIconsSet; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.R; import com.android.inputmethod.latin.StaticInnerHandlerWrapper; @@ -103,7 +101,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final int mKeyPreviewLayoutId; protected final KeyPreviewDrawParams mKeyPreviewDrawParams; private boolean mShowKeyPreviewPopup = true; - private final int mDelayBeforePreview; private int mDelayAfterPreview; private ViewGroup mPreviewPlacer; @@ -135,8 +132,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { private final DrawingHandler mDrawingHandler = new DrawingHandler(this); public static class DrawingHandler extends StaticInnerHandlerWrapper<KeyboardView> { - private static final int MSG_SHOW_KEY_PREVIEW = 1; - private static final int MSG_DISMISS_KEY_PREVIEW = 2; + private static final int MSG_DISMISS_KEY_PREVIEW = 1; public DrawingHandler(KeyboardView outerInstance) { super(outerInstance); @@ -148,35 +144,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { if (keyboardView == null) return; final PointerTracker tracker = (PointerTracker) msg.obj; switch (msg.what) { - case MSG_SHOW_KEY_PREVIEW: - keyboardView.showKey(tracker); - break; case MSG_DISMISS_KEY_PREVIEW: tracker.getKeyPreviewText().setVisibility(View.INVISIBLE); break; } } - public void showKeyPreview(long delay, PointerTracker tracker) { - removeMessages(MSG_SHOW_KEY_PREVIEW); - final KeyboardView keyboardView = getOuterInstance(); - if (keyboardView == null) return; - if (tracker.getKeyPreviewText().getVisibility() == VISIBLE || delay == 0) { - // Show right away, if it's already visible and finger is moving around - keyboardView.showKey(tracker); - } else { - sendMessageDelayed(obtainMessage(MSG_SHOW_KEY_PREVIEW, tracker), delay); - } - } - - public void cancelShowKeyPreview(PointerTracker tracker) { - removeMessages(MSG_SHOW_KEY_PREVIEW, tracker); - } - - public void cancelAllShowKeyPreviews() { - removeMessages(MSG_SHOW_KEY_PREVIEW); - } - public void dismissKeyPreview(long delay, PointerTracker tracker) { sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, tracker), delay); } @@ -190,7 +163,6 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { } public void cancelAllMessages() { - cancelAllShowKeyPreviews(); cancelAllDismissKeyPreviews(); } } @@ -295,6 +267,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { public final int mPreviewOffset; public final int mPreviewHeight; public final Typeface mKeyTextStyle; + public final int mLingerTimeout; private final float mPreviewTextRatio; private final float mKeyLetterRatio; @@ -324,6 +297,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { R.styleable.KeyboardView_keyPreviewHeight, 80); mPreviewTextRatio = getRatio(a, R.styleable.KeyboardView_keyPreviewTextRatio); mPreviewTextColor = a.getColor(R.styleable.KeyboardView_keyPreviewTextColor, 0); + mLingerTimeout = a.getInt(R.styleable.KeyboardView_keyPreviewLingerTimeout, 0); mKeyLetterRatio = keyDrawParams.mKeyLetterRatio; mKeyTextStyle = keyDrawParams.mKeyTextStyle; @@ -363,10 +337,7 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { mBackgroundDimAmount = a.getFloat(R.styleable.KeyboardView_backgroundDimAmount, 0.5f); a.recycle(); - final Resources res = getResources(); - - mDelayBeforePreview = res.getInteger(R.integer.config_delay_before_preview); - mDelayAfterPreview = res.getInteger(R.integer.config_delay_after_preview); + mDelayAfterPreview = mKeyPreviewDrawParams.mLingerTimeout; mPaint.setAntiAlias(true); mPaint.setTextAlign(Align.CENTER); @@ -386,8 +357,8 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { * @param keyboard the keyboard to display in this view */ public void setKeyboard(Keyboard keyboard) { - // Remove any pending dismissing preview - mDrawingHandler.cancelAllShowKeyPreviews(); + // Remove any pending messages. + mDrawingHandler.cancelAllMessages(); if (mKeyboard != null) { PointerTracker.dismissAllKeyPreviews(); } @@ -841,18 +812,12 @@ public class KeyboardView extends View implements PointerTracker.DrawingProxy { @Override public void showKeyPreview(PointerTracker tracker) { if (mShowKeyPreviewPopup) { - mDrawingHandler.showKeyPreview(mDelayBeforePreview, tracker); + showKey(tracker); } } @Override - public void cancelShowKeyPreview(PointerTracker tracker) { - mDrawingHandler.cancelShowKeyPreview(tracker); - } - - @Override public void dismissKeyPreview(PointerTracker tracker) { - mDrawingHandler.cancelShowKeyPreview(tracker); mDrawingHandler.dismissKeyPreview(mDelayAfterPreview, tracker); } diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java index f5b282df3..aee356a0c 100644 --- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java +++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java @@ -18,7 +18,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; import android.content.pm.PackageManager; -import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; @@ -103,6 +102,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke new WeakHashMap<Key, MoreKeysPanel>(); private final boolean mConfigShowMiniKeyboardAtTouchedPoint; + private final PointerTrackerParams mPointerTrackerParams; private final boolean mIsSpacebarTriggeringPopupByLongPress; private final SuddenJumpingTouchEventHandler mTouchScreenRegulator; @@ -114,7 +114,7 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke // To detect double tap. protected GestureDetector mGestureDetector; - private final KeyTimerHandler mKeyTimerHandler = new KeyTimerHandler(this); + private final KeyTimerHandler mKeyTimerHandler; private static class KeyTimerHandler extends StaticInnerHandlerWrapper<LatinKeyboardView> implements TimerProxy { @@ -126,11 +126,9 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke private final int mKeyRepeatInterval; private boolean mInKeyRepeat; - public KeyTimerHandler(LatinKeyboardView outerInstance) { + public KeyTimerHandler(LatinKeyboardView outerInstance, int keyRepeatInterval) { super(outerInstance); - // TODO: This should be the attribute of LatinKeyboardView. - final Resources res = outerInstance.getContext().getResources(); - mKeyRepeatInterval = res.getInteger(R.integer.config_key_repeat_interval); + mKeyRepeatInterval = keyRepeatInterval; } @Override @@ -253,6 +251,49 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke } } + public static class PointerTrackerParams { + public final boolean mSlidingKeyInputEnabled; + public final int mKeyRepeatStartTimeout; + public final int mLongPressKeyTimeout; + public final int mLongPressShiftKeyTimeout; + public final int mLongPressSpaceKeyTimeout; + public final int mIgnoreSpecialKeyTimeout; + public final int mTouchNoiseThresholdTime; + public final float mTouchNoiseThresholdDistance; + + public static final PointerTrackerParams DEFAULT = new PointerTrackerParams(); + + private PointerTrackerParams() { + mSlidingKeyInputEnabled = false; + mKeyRepeatStartTimeout = 0; + mLongPressKeyTimeout = 0; + mLongPressShiftKeyTimeout = 0; + mLongPressSpaceKeyTimeout = 0; + mIgnoreSpecialKeyTimeout = 0; + mTouchNoiseThresholdTime =0; + mTouchNoiseThresholdDistance = 0; + } + + public PointerTrackerParams(TypedArray latinKeyboardViewAttr) { + mSlidingKeyInputEnabled = latinKeyboardViewAttr.getBoolean( + R.styleable.LatinKeyboardView_slidingKeyInputEnable, false); + mKeyRepeatStartTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_keyRepeatStartTimeout, 0); + mLongPressKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressKeyTimeout, 0); + mLongPressShiftKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressShiftKeyTimeout, 0); + mLongPressSpaceKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_longPressSpaceKeyTimeout, 0); + mIgnoreSpecialKeyTimeout = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_ignoreSpecialKeyTimeout, 0); + mTouchNoiseThresholdTime = latinKeyboardViewAttr.getInt( + R.styleable.LatinKeyboardView_touchNoiseThresholdTime, 0); + mTouchNoiseThresholdDistance = latinKeyboardViewAttr.getDimension( + R.styleable.LatinKeyboardView_touchNoiseThresholdDistance, 0); + } + } + public LatinKeyboardView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.latinKeyboardViewStyle); } @@ -262,14 +303,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mTouchScreenRegulator = new SuddenJumpingTouchEventHandler(getContext(), this); - final Resources res = getResources(); - // TODO: This should be the attribute of LatinKeyboardView. - mConfigShowMiniKeyboardAtTouchedPoint = res.getBoolean( - R.bool.config_show_mini_keyboard_at_touched_point); - // TODO: This should be the attribute of LatinKeyboardView. - final float keyHysteresisDistance = res.getDimension(R.dimen.key_hysteresis_distance); - mKeyDetector = new KeyDetector(keyHysteresisDistance); - final boolean ignoreMultitouch = true; mGestureDetector = new GestureDetector( getContext(), new DoubleTapListener(), null, ignoreMultitouch); @@ -280,11 +313,6 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke PointerTracker.init(mHasDistinctMultitouch, getContext()); - // TODO: This should be the attribute of LatinKeyboardView. - final int longPressSpaceKeyTimeout = - res.getInteger(R.integer.config_long_press_space_key_timeout); - mIsSpacebarTriggeringPopupByLongPress = (longPressSpaceKeyTimeout > 0); - final TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.LatinKeyboardView, defStyle, R.style.LatinKeyboardView); mAutoCorrectionSpacebarLedEnabled = a.getBoolean( @@ -296,7 +324,22 @@ public class LatinKeyboardView extends KeyboardView implements PointerTracker.Ke mSpacebarTextColor = a.getColor(R.styleable.LatinKeyboardView_spacebarTextColor, 0); mSpacebarTextShadowColor = a.getColor( R.styleable.LatinKeyboardView_spacebarTextShadowColor, 0); + + mPointerTrackerParams = new PointerTrackerParams(a); + mIsSpacebarTriggeringPopupByLongPress = ( + mPointerTrackerParams.mLongPressSpaceKeyTimeout > 0); + + final float keyHysteresisDistance = a.getDimension( + R.styleable.LatinKeyboardView_keyHysteresisDistance, 0); + mKeyDetector = new KeyDetector(keyHysteresisDistance); + final int keyRepeatInterval = a.getInt( + R.styleable.LatinKeyboardView_keyRepeatInterval, 0); + mKeyTimerHandler = new KeyTimerHandler(this, keyRepeatInterval); + mConfigShowMiniKeyboardAtTouchedPoint = a.getBoolean( + R.styleable.LatinKeyboardView_showMiniKeyboardAtTouchedPoint, false); a.recycle(); + + PointerTracker.setParameters(mPointerTrackerParams); } public void startIgnoringDoubleTap() { diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 274bd0b31..a75b8f9e6 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -17,7 +17,6 @@ package com.android.inputmethod.keyboard; import android.content.Context; -import android.content.res.Resources; import android.os.SystemClock; import android.util.Log; import android.view.MotionEvent; @@ -25,7 +24,6 @@ import android.widget.TextView; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; -import com.android.inputmethod.latin.R; import java.util.ArrayList; import java.util.List; @@ -69,7 +67,6 @@ public class PointerTracker { public void invalidateKey(Key key); public TextView inflateKeyPreviewText(); public void showKeyPreview(PointerTracker tracker); - public void cancelShowKeyPreview(PointerTracker tracker); public void dismissKeyPreview(PointerTracker tracker); } @@ -98,14 +95,8 @@ public class PointerTracker { } private static KeyboardSwitcher sKeyboardSwitcher; - private static boolean sConfigSlidingKeyInputEnabled; - // Timing constants - private static int sDelayBeforeKeyRepeatStart; - private static int sLongPressKeyTimeout; - private static int sLongPressShiftKeyTimeout; - private static int sLongPressSpaceKeyTimeout; - private static int sIgnoreSpecialKeyTimeout; - private static int sTouchNoiseThresholdMillis; + // Parameters for pointer handling. + private static LatinKeyboardView.PointerTrackerParams sParams; private static int sTouchNoiseThresholdDistanceSquared; private static final List<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); @@ -169,20 +160,14 @@ public class PointerTracker { sPointerTrackerQueue = null; } - final Resources res = context.getResources(); - sConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled); - sDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); - sLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout); - sLongPressShiftKeyTimeout = res.getInteger(R.integer.config_long_press_shift_key_timeout); - sLongPressSpaceKeyTimeout = res.getInteger(R.integer.config_long_press_space_key_timeout); - sIgnoreSpecialKeyTimeout = res.getInteger(R.integer.config_ignore_special_key_timeout); - sTouchNoiseThresholdMillis = res.getInteger(R.integer.config_touch_noise_threshold_millis); + setParameters(LatinKeyboardView.PointerTrackerParams.DEFAULT); + sKeyboardSwitcher = KeyboardSwitcher.getInstance(); + } - final float touchNoiseThresholdDistance = res.getDimension( - R.dimen.config_touch_noise_threshold_distance); + public static void setParameters(LatinKeyboardView.PointerTrackerParams params) { + sParams = params; sTouchNoiseThresholdDistanceSquared = (int)( - touchNoiseThresholdDistance * touchNoiseThresholdDistance); - sKeyboardSwitcher = KeyboardSwitcher.getInstance(); + params.mTouchNoiseThresholdDistance * params.mTouchNoiseThresholdDistance); } public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { @@ -278,7 +263,7 @@ public class PointerTracker { mListener.onCodeInput(code, keyCodes, x, y); } if (!key.altCodeWhileTyping() && !key.isModifier()) { - mTimerProxy.startKeyTypedTimer(sIgnoreSpecialKeyTimeout); + mTimerProxy.startKeyTypedTimer(sParams.mIgnoreSpecialKeyTimeout); } } } @@ -453,7 +438,7 @@ public class PointerTracker { setKeyDetectorInner(handler.getKeyDetector()); // Naive up-to-down noise filter. final long deltaT = eventTime - mUpTime; - if (deltaT < sTouchNoiseThresholdMillis) { + if (deltaT < sParams.mTouchNoiseThresholdTime) { final int dx = x - mLastX; final int dy = y - mLastY; final int distanceSquared = (dx * dx + dy * dy); @@ -483,7 +468,7 @@ public class PointerTracker { Key key = onDownKey(x, y, eventTime); // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. - mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled + mIsAllowedSlidingKeyInput = sParams.mSlidingKeyInputEnabled || (key != null && key.isModifier()) || mKeyDetector.alwaysAllowsSlidingInput(); mKeyboardLayoutHasBeenChanged = false; @@ -620,7 +605,6 @@ public class PointerTracker { private void onUpEventInternal(int x, int y, long eventTime) { mTimerProxy.cancelKeyTimers(); - mDrawingProxy.cancelShowKeyPreview(this); mIsInSlidingKeyInput = false; final int keyX, keyY; if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { @@ -673,7 +657,6 @@ public class PointerTracker { private void onCancelEventInternal() { mTimerProxy.cancelKeyTimers(); - mDrawingProxy.cancelShowKeyPreview(this); setReleasedKeyGraphics(mCurrentKey); mIsInSlidingKeyInput = false; if (mIsShowingMoreKeysPanel) { @@ -685,7 +668,7 @@ public class PointerTracker { private void startRepeatKey(Key key) { if (key != null && key.isRepeatable()) { onRepeatKey(key); - mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, this); + mTimerProxy.startKeyRepeatTimer(sParams.mKeyRepeatStartTimeout, this); mIsRepeatableKey = true; } else { mIsRepeatableKey = false; @@ -715,12 +698,12 @@ public class PointerTracker { private void startLongPressTimer(Key key) { if (key == null) return; if (key.mCode == Keyboard.CODE_SHIFT) { - if (sLongPressShiftKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, this); + if (sParams.mLongPressShiftKeyTimeout > 0) { + mTimerProxy.startLongPressTimer(sParams.mLongPressShiftKeyTimeout, this); } } else if (key.mCode == Keyboard.CODE_SPACE) { - if (sLongPressSpaceKeyTimeout > 0) { - mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, this); + if (sParams.mLongPressSpaceKeyTimeout > 0) { + mTimerProxy.startLongPressTimer(sParams.mLongPressSpaceKeyTimeout, this); } } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { // We need not start long press timer on the key which has manual temporary upper case @@ -728,9 +711,9 @@ public class PointerTracker { return; } else if (sKeyboardSwitcher.isInMomentarySwitchState()) { // We use longer timeout for sliding finger input started from the symbols mode key. - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, this); + mTimerProxy.startLongPressTimer(sParams.mLongPressKeyTimeout * 3, this); } else { - mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, this); + mTimerProxy.startLongPressTimer(sParams.mLongPressKeyTimeout, this); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java index 38c31adce..a89356c50 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java +++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java @@ -43,8 +43,7 @@ public class KeyboardState { public void setAlphabetManualShiftedKeyboard(); public void setAlphabetAutomaticShiftedKeyboard(); public void setAlphabetShiftLockedKeyboard(); - // TODO: Add this. - //public void setAlphabetShiftLockShiftedKeyboard(); + public void setAlphabetShiftLockShiftedKeyboard(); public void setSymbolsKeyboard(); public void setSymbolsShiftedKeyboard(); @@ -157,14 +156,10 @@ public class KeyboardState { } } - // TODO: Remove this method. - public boolean isShiftLocked() { - return mAlphabetShiftState.isShiftLocked(); - } - private static final int UNSHIFT = 0; private static final int MANUAL_SHIFT = 1; private static final int AUTOMATIC_SHIFT = 2; + private static final int SHIFT_LOCK_SHIFTED = 3; private void setShifted(int shiftMode) { if (DEBUG_ACTION) { @@ -198,6 +193,10 @@ public class KeyboardState { mSwitchActions.setAlphabetKeyboard(); } break; + case SHIFT_LOCK_SHIFTED: + mAlphabetShiftState.setShifted(true); + mSwitchActions.setAlphabetShiftLockShiftedKeyboard(); + break; } } @@ -349,7 +348,7 @@ public class KeyboardState { if (mAlphabetShiftState.isShiftLocked()) { // Shift key is pressed while caps lock state, we will treat this state as shifted // caps lock state and mark as if shift key pressed while normal state. - setShifted(MANUAL_SHIFT); + setShifted(SHIFT_LOCK_SHIFTED); mShiftKeyState.onPress(); } else if (mAlphabetShiftState.isAutomaticTemporaryUpperCase()) { // Shift key is pressed while automatic temporary upper case, we have to move to diff --git a/java/src/com/android/inputmethod/latin/BinaryDictionary.java b/java/src/com/android/inputmethod/latin/BinaryDictionary.java index 3692ac179..b82400046 100644 --- a/java/src/com/android/inputmethod/latin/BinaryDictionary.java +++ b/java/src/com/android/inputmethod/latin/BinaryDictionary.java @@ -162,7 +162,7 @@ public class BinaryDictionary extends Dictionary { } if (len > 0) { callback.addWord(mOutputChars_bigrams, start, len, mBigramScores[j], - mDicTypeId, DataType.BIGRAM); + mDicTypeId, Dictionary.BIGRAM); } } } @@ -182,7 +182,7 @@ public class BinaryDictionary extends Dictionary { } if (len > 0) { callback.addWord(mOutputChars, start, len, mScores[j], mDicTypeId, - DataType.UNIGRAM); + Dictionary.UNIGRAM); } } } diff --git a/java/src/com/android/inputmethod/latin/Dictionary.java b/java/src/com/android/inputmethod/latin/Dictionary.java index c35b42877..79bf33850 100644 --- a/java/src/com/android/inputmethod/latin/Dictionary.java +++ b/java/src/com/android/inputmethod/latin/Dictionary.java @@ -33,9 +33,8 @@ public abstract class Dictionary { */ protected static final int FULL_WORD_SCORE_MULTIPLIER = 2; - public static enum DataType { - UNIGRAM, BIGRAM - } + public static final int UNIGRAM = 0; + public static final int BIGRAM = 1; /** * Interface to be implemented by classes requesting words to be fetched from the dictionary. @@ -51,11 +50,11 @@ public abstract class Dictionary { * @param score the score of occurrence. This is normalized between 1 and 255, but * can exceed those limits * @param dicTypeId of the dictionary where word was from - * @param dataType tells type of this data + * @param dataType tells type of this data, either UNIGRAM or BIGRAM * @return true if the word was added, false if no more words are required */ boolean addWord(char[] word, int wordOffset, int wordLength, int score, int dicTypeId, - DataType dataType); + int dataType); } /** @@ -64,7 +63,7 @@ public abstract class Dictionary { * @param composer the key sequence to match * @param callback the callback object to send matched words to as possible candidates * @param proximityInfo the object for key proximity. May be ignored by some implementations. - * @see WordCallback#addWord(char[], int, int, int, int, DataType) + * @see WordCallback#addWord(char[], int, int, int, int, int) */ abstract public void getWords(final WordComposer composer, final WordCallback callback, final ProximityInfo proximityInfo); diff --git a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java index 7eec8e2ca..8e8adc1c2 100644 --- a/java/src/com/android/inputmethod/latin/ExpandableDictionary.java +++ b/java/src/com/android/inputmethod/latin/ExpandableDictionary.java @@ -301,7 +301,7 @@ public class ExpandableDictionary extends Dictionary { finalFreq = computeSkippedWordFinalFreq(freq, snr, mInputLength); } if (!callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, - DataType.UNIGRAM)) { + Dictionary.UNIGRAM)) { return; } } @@ -342,7 +342,7 @@ public class ExpandableDictionary extends Dictionary { snr * addedAttenuation, mInputLength); } callback.addWord(word, 0, depth + 1, finalFreq, mDicTypeId, - DataType.UNIGRAM); + Dictionary.UNIGRAM); } } if (children != null) { @@ -506,7 +506,7 @@ public class ExpandableDictionary extends Dictionary { } while (node != null); callback.addWord(mLookedUpString, index, MAX_WORD_LENGTH - index, freq, mDicTypeId, - DataType.BIGRAM); + Dictionary.BIGRAM); } } diff --git a/java/src/com/android/inputmethod/latin/LastComposedWord.java b/java/src/com/android/inputmethod/latin/LastComposedWord.java new file mode 100644 index 000000000..0c8c88f50 --- /dev/null +++ b/java/src/com/android/inputmethod/latin/LastComposedWord.java @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +package com.android.inputmethod.latin; + +import android.text.TextUtils; + +import java.util.ArrayList; + +/** + * This class encapsulates data about a word previously composed, but that has been + * committed already. This is used for resuming suggestion, and cancel auto-correction. + */ +public class LastComposedWord { + // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with + // no hinting from the IME. It happens when some external event happens (rotating the device, + // for example) or when auto-correction is off by settings or editor attributes. + public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; + // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. + public static final int COMMIT_TYPE_MANUAL_PICK = 1; + // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best + // for the current user input. It may be different from what the user typed (true auto-correct) + // or it may be exactly what the user typed if it's in the dictionary or the IME does not have + // enough confidence in any suggestion to auto-correct (auto-correct to typed word). + public static final int COMMIT_TYPE_DECIDED_WORD = 2; + // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling + // an auto-correction. + public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; + + public final ArrayList<int[]> mCodes; + public final int[] mXCoordinates; + public final int[] mYCoordinates; + public final String mTypedWord; + public final String mAutoCorrection; + + private boolean mActive; + + public static final LastComposedWord NOT_A_COMPOSED_WORD = + new LastComposedWord(null, null, null, "", ""); + + public LastComposedWord(final ArrayList<int[]> codes, final int[] xCoordinates, + final int[] yCoordinates, final String typedWord, final String autoCorrection) { + mCodes = codes; + mXCoordinates = xCoordinates; + mYCoordinates = yCoordinates; + mTypedWord = typedWord; + mAutoCorrection = autoCorrection; + mActive = true; + } + + public void deactivate() { + mActive = false; + } + + public boolean canCancelAutoCorrect() { + return mActive && !TextUtils.isEmpty(mAutoCorrection) + && !TextUtils.equals(mTypedWord, mAutoCorrection); + } +} diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index d59497d6a..2e7e82637 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -104,7 +104,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar */ public static final String IME_OPTION_NO_SETTINGS_KEY = "noSettingsKey"; - // TODO: Remove this private option. /** * The private IME option used to indicate that the given text field needs * ASCII code points input. @@ -200,6 +199,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar private UserUnigramDictionary mUserUnigramDictionary; private boolean mIsUserDictionaryAvailable; + private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; private WordComposer mWordComposer = new WordComposer(); private int mCorrectionMode; @@ -729,6 +729,17 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar : String.format("inputType=0x%08x imeOptions=0x%08x", editorInfo.inputType, editorInfo.imeOptions))); } + if (Utils.inPrivateImeOptions(null, IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo)) { + Log.w(TAG, "Deprecated private IME option specified: " + + editorInfo.privateImeOptions); + Log.w(TAG, "Use " + getPackageName() + "." + IME_OPTION_NO_MICROPHONE + " instead"); + } + if (Utils.inPrivateImeOptions(getPackageName(), IME_OPTION_FORCE_ASCII, editorInfo)) { + Log.w(TAG, "Deprecated private IME option specified: " + + editorInfo.privateImeOptions); + Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead"); + } + LatinImeLogger.onStartInputView(editorInfo); // In landscape mode, this method gets called without the input view being created. if (inputView == null) { @@ -759,7 +770,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar inputView.closing(); mEnteredText = null; - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); mDeleteCount = 0; mSpaceState = SPACE_STATE_NONE; @@ -871,7 +882,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (((mWordComposer.isComposingWord()) || mVoiceProxy.isVoiceInputHighlighted()) && (selectionChanged || candidatesCleared)) { - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); updateSuggestions(); final InputConnection ic = getCurrentInputConnection(); if (ic != null) { @@ -880,7 +891,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mComposingStateManager.onFinishComposingText(); mVoiceProxy.setVoiceInputHighlighted(false); } else if (!mWordComposer.isComposingWord()) { - mWordComposer.reset(); + // TODO: is the following reset still needed, given that we are not composing + // a word? + resetComposingState(true /* alsoResetLastComposedWord */); updateSuggestions(); } } @@ -964,7 +977,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar .setHasMinimalSuggestion(false); // When in fullscreen mode, show completions generated by the application setSuggestions(builder.build()); - mWordComposer.deleteAutoCorrection(); + // TODO: is this the right thing to do? What should we auto-correct to in + // this case? This says to keep whatever the user typed. + mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); setSuggestionStripShown(true); } } @@ -1083,10 +1098,16 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar return super.onKeyUp(keyCode, event); } + private void resetComposingState(final boolean alsoResetLastComposedWord) { + mWordComposer.reset(); + if (alsoResetLastComposedWord) + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; + } + public void commitTyped(final InputConnection ic) { if (!mWordComposer.isComposingWord()) return; final CharSequence typedWord = mWordComposer.getTypedWord(); - mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_USER_TYPED_WORD); + mLastComposedWord = mWordComposer.commitWord(LastComposedWord.COMMIT_TYPE_USER_TYPED_WORD); if (typedWord.length() > 0) { if (ic != null) { ic.commitText(typedWord, 1); @@ -1253,6 +1274,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.cancelDoubleSpacesTimer(); } + boolean didAutoCorrect = false; switch (primaryCode) { case Keyboard.CODE_DELETE: mSpaceState = SPACE_STATE_NONE; @@ -1289,7 +1311,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar default: mSpaceState = SPACE_STATE_NONE; if (mSettingsValues.isWordSeparator(primaryCode)) { - handleSeparator(primaryCode, x, y, spaceState); + didAutoCorrect = handleSeparator(primaryCode, x, y, spaceState); } else { handleCharacter(primaryCode, keyCodes, x, y, spaceState); } @@ -1298,6 +1320,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } switcher.onCodeInput(primaryCode); // Reset after any single keystroke + if (!didAutoCorrect) + mLastComposedWord.deactivate(); mEnteredText = null; } @@ -1315,7 +1339,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mKeyboardSwitcher.onCodeInput(Keyboard.CODE_OUTPUT_TEXT); mSpaceState = SPACE_STATE_NONE; mEnteredText = text; - mWordComposer.reset(); + resetComposingState(true /* alsoResetLastComposedWord */); } @Override @@ -1373,7 +1397,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // resuming here. The behavior needs to be different according to text field types, // and it would be much clearer to test for them explicitly here rather than // relying on implicit values like "whether the suggestion strip is displayed". - if (mWordComposer.didAutoCorrectToAnotherWord()) { + if (mLastComposedWord.canCancelAutoCorrect()) { Utils.Stats.onAutoCorrectionCancellation(); cancelAutoCorrect(ic); return; @@ -1485,7 +1509,11 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // separator and it should be treated as a normal character, except in the first // position where it should not start composing a word. isComposingWord = (Keyboard.CODE_SINGLE_QUOTE != code); - mWordComposer.reset(); + // Here we don't need to reset the last composed word. It will be reset + // when we commit this one, if we ever do; if on the other hand we backspace + // it entirely and resume suggestions on the previous word, we'd like to still + // have touch coordinates for it. + resetComposingState(false /* alsoResetLastComposedWord */); clearSuggestions(); mComposingStateManager.onFinishComposingText(); } @@ -1537,7 +1565,8 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } } - private void handleSeparator(final int primaryCode, final int x, final int y, + // Returns true if we did an autocorrection, false otherwise. + private boolean handleSeparator(final int primaryCode, final int x, final int y, final int spaceState) { mVoiceProxy.handleSeparator(); mComposingStateManager.onFinishComposingText(); @@ -1548,6 +1577,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar mHandler.postUpdateSuggestions(); } + boolean didAutoCorrect = false; // Handle separator final InputConnection ic = getCurrentInputConnection(); if (ic != null) { @@ -1562,6 +1592,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar && !mInputAttributes.mInputTypeNoAutoCorrect; if (shouldAutoCorrect && primaryCode != Keyboard.CODE_SINGLE_QUOTE) { commitCurrentAutoCorrection(primaryCode, ic); + didAutoCorrect = true; } else { commitTyped(ic); } @@ -1617,12 +1648,13 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar if (ic != null) { ic.endBatchEdit(); } + return didAutoCorrect; } private CharSequence getTextWithUnderline(final CharSequence text) { return mComposingStateManager.isAutoCorrectionIndicatorOn() ? SuggestionSpanUtils.getTextWithAutoCorrectionIndicatorUnderline(this, text) - : mWordComposer.getTypedWord(); + : text; } private void handleClose() { @@ -1837,7 +1869,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } Utils.Stats.onAutoCorrection(typedWord, autoCorrection.toString(), separatorCodePoint); mExpectingUpdateSelection = true; - commitChosenWord(autoCorrection, WordComposer.COMMIT_TYPE_DECIDED_WORD); + commitChosenWord(autoCorrection, LastComposedWord.COMMIT_TYPE_DECIDED_WORD); // Add the word to the user unigram dictionary if it's not a known word addToUserUnigramAndBigramDictionaries(autoCorrection, UserUnigramDictionary.FREQUENCY_FOR_TYPED); @@ -1907,7 +1939,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar LatinImeLogger.logOnManualSuggestion(mWordComposer.getTypedWord().toString(), suggestion.toString(), index, suggestions.mWords); mExpectingUpdateSelection = true; - commitChosenWord(suggestion, WordComposer.COMMIT_TYPE_MANUAL_PICK); + commitChosenWord(suggestion, LastComposedWord.COMMIT_TYPE_MANUAL_PICK); // Add the word to the auto dictionary if it's not a known word if (index == 0) { addToUserUnigramAndBigramDictionaries(suggestion, @@ -1975,9 +2007,9 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar } // TODO: figure out here if this is an auto-correct or if the best word is actually // what user typed. Note: currently this is done much later in - // WordComposer#didAutoCorrectToAnotherWord by string equality of the remembered + // LastComposedWord#canCancelAutoCorrect by string equality of the remembered // strings. - mWordComposer.onCommitWord(commitType); + mLastComposedWord = mWordComposer.commitWord(commitType); } private static final WordComposer sEmptyWordComposer = new WordComposer(); @@ -2141,12 +2173,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // "ic" must not be null private void cancelAutoCorrect(final InputConnection ic) { - mWordComposer.resumeSuggestionOnKeptWord(); - final String originallyTypedWord = mWordComposer.getTypedWord(); - final CharSequence autoCorrectedTo = mWordComposer.getAutoCorrectionOrNull(); + final String originallyTypedWord = mLastComposedWord.mTypedWord; + final CharSequence autoCorrectedTo = mLastComposedWord.mAutoCorrection; final int cancelLength = autoCorrectedTo.length(); final CharSequence separator = ic.getTextBeforeCursor(1, 0); if (DEBUG) { + if (mWordComposer.isComposingWord()) { + throw new RuntimeException("cancelAutoCorrect, but we are composing a word"); + } final String wordBeforeCursor = ic.getTextBeforeCursor(cancelLength + 1, 0).subSequence(0, cancelLength) .toString(); @@ -2165,8 +2199,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar ic.commitText(originallyTypedWord, 1); // Re-insert the separator ic.commitText(separator, 1); - mWordComposer.deleteAutoCorrection(); - mWordComposer.onCommitWord(WordComposer.COMMIT_TYPE_CANCEL_AUTO_CORRECT); + mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD; Utils.Stats.onSeparator(separator.charAt(0), WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); mHandler.cancelUpdateBigramPredictions(); @@ -2180,7 +2213,7 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar // Note: in the interest of code simplicity, we may want to just call // restartSuggestionsOnWordBeforeCursorIfAtEndOfWord instead, but retrieving // the old WordComposer allows to reuse the actual typed coordinates. - mWordComposer.resumeSuggestionOnKeptWord(); + mWordComposer.resumeSuggestionOnLastComposedWord(mLastComposedWord); // We resume suggestion, and then we want to set the composing text to the content // of the word composer again. But since we just manually picked a word, there is // no composing text at the moment, so we have to delete the word before we set a @@ -2229,10 +2262,14 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar final CharSequence textBeforeCursor = ic.getTextBeforeCursor(2, 0); // NOTE: This does not work with surrogate pairs. Hopefully when the keyboard is able to // enter surrogate pairs this code will have been removed. - if (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1)) { - // We should not have come here if the text before the cursor is not a space. - throw new RuntimeException("Tried to revert a swap of punctuation but we didn't " + if (TextUtils.isEmpty(textBeforeCursor) + || (Keyboard.CODE_SPACE != textBeforeCursor.charAt(1))) { + // We may only come here if the application is changing the text while we are typing. + // This is quite a broken case, but not logically impossible, so we shouldn't crash, + // but some debugging log may be in order. + Log.d(TAG, "Tried to revert a swap of punctuation but we didn't " + "find a space just before the cursor."); + return false; } ic.beginBatchEdit(); ic.deleteSurroundingText(2, 0); diff --git a/java/src/com/android/inputmethod/latin/LatinImeLogger.java b/java/src/com/android/inputmethod/latin/LatinImeLogger.java index 6f1adfe71..e3dadf250 100644 --- a/java/src/com/android/inputmethod/latin/LatinImeLogger.java +++ b/java/src/com/android/inputmethod/latin/LatinImeLogger.java @@ -21,7 +21,6 @@ import android.content.SharedPreferences; import android.view.inputmethod.EditorInfo; import com.android.inputmethod.keyboard.Keyboard; -import com.android.inputmethod.latin.Dictionary.DataType; import java.util.List; @@ -75,7 +74,7 @@ public class LatinImeLogger implements SharedPreferences.OnSharedPreferenceChang public static void onStartSuggestion(CharSequence previousWords) { } - public static void onAddSuggestedWord(String word, int typeId, DataType dataType) { + public static void onAddSuggestedWord(String word, int typeId, int dataType) { } public static void onSetKeyboard(Keyboard kb) { diff --git a/java/src/com/android/inputmethod/latin/Settings.java b/java/src/com/android/inputmethod/latin/Settings.java index 5af21452a..d32310096 100644 --- a/java/src/com/android/inputmethod/latin/Settings.java +++ b/java/src/com/android/inputmethod/latin/Settings.java @@ -218,7 +218,7 @@ public class Settings extends InputMethodSettingsActivity res.getString(R.string.key_preview_popup_dismiss_default_delay), }; final String popupDismissDelayDefaultValue = Integer.toString(res.getInteger( - R.integer.config_delay_after_preview)); + R.integer.config_key_preview_linger_timeout)); mKeyPreviewPopupDismissDelay.setEntries(entries); mKeyPreviewPopupDismissDelay.setEntryValues( new String[] { "0", popupDismissDelayDefaultValue }); diff --git a/java/src/com/android/inputmethod/latin/SettingsValues.java b/java/src/com/android/inputmethod/latin/SettingsValues.java index 0ae28d3fc..e6ef3962e 100644 --- a/java/src/com/android/inputmethod/latin/SettingsValues.java +++ b/java/src/com/android/inputmethod/latin/SettingsValues.java @@ -124,7 +124,7 @@ public class SettingsValues { mUsabilityStudyMode = getUsabilityStudyMode(prefs); mKeyPreviewPopupDismissDelayRawValue = prefs.getString( Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(res.getInteger(R.integer.config_delay_after_preview))); + Integer.toString(res.getInteger(R.integer.config_key_preview_linger_timeout))); mUseContactsDict = prefs.getBoolean(Settings.PREF_KEY_USE_CONTACTS_DICT, true); mAutoCorrectEnabled = isAutoCorrectEnabled(res, mAutoCorrectionThresholdRawValue); mBigramSuggestionEnabled = mAutoCorrectEnabled @@ -234,7 +234,8 @@ public class SettingsValues { Resources resources) { // TODO: use mKeyPreviewPopupDismissDelayRawValue instead of reading it again here. return Integer.parseInt(sp.getString(Settings.PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY, - Integer.toString(resources.getInteger(R.integer.config_delay_after_preview)))); + Integer.toString(resources.getInteger( + R.integer.config_key_preview_linger_timeout)))); } private static boolean isBigramSuggestionEnabled(final SharedPreferences sp, diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 8e0d031f4..f6e177aaf 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -298,7 +298,7 @@ public class Suggest implements Dictionary.WordCallback { if (typedWord != null) { // Treating USER_TYPED as UNIGRAM suggestion for logging now. LatinImeLogger.onAddSuggestedWord(typedWord, Suggest.DIC_USER_TYPED, - Dictionary.DataType.UNIGRAM); + Dictionary.UNIGRAM); } mConsideredWord = consideredWord; @@ -417,12 +417,12 @@ public class Suggest implements Dictionary.WordCallback { @Override public boolean addWord(final char[] word, final int offset, final int length, int score, - final int dicTypeId, final Dictionary.DataType dataType) { - Dictionary.DataType dataTypeForLog = dataType; + final int dicTypeId, final int dataType) { + int dataTypeForLog = dataType; final ArrayList<CharSequence> suggestions; final int[] sortedScores; final int prefMaxSuggestions; - if(dataType == Dictionary.DataType.BIGRAM) { + if (dataType == Dictionary.BIGRAM) { suggestions = mBigramSuggestions; sortedScores = mBigramScores; prefMaxSuggestions = PREF_MAX_BIGRAMS; @@ -450,11 +450,11 @@ public class Suggest implements Dictionary.WordCallback { } } } else { - if (dataType == Dictionary.DataType.UNIGRAM) { + if (dataType == Dictionary.UNIGRAM) { // Check if the word was already added before (by bigram data) int bigramSuggestion = searchBigramSuggestion(word,offset,length); if(bigramSuggestion >= 0) { - dataTypeForLog = Dictionary.DataType.BIGRAM; + dataTypeForLog = Dictionary.BIGRAM; // turn freq from bigram into multiplier specified above double multiplier = (((double) mBigramScores[bigramSuggestion]) / MAXIMUM_BIGRAM_FREQUENCY) diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index e95dcfdc9..b96b0842a 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -33,64 +33,17 @@ public class WordComposer { public static final int NOT_A_CODE = KeyDetector.NOT_A_CODE; public static final int NOT_A_COORDINATE = -1; - // TODO: Straighten out commit behavior so that the flags here are more understandable, - // and possibly adjust their names. - // COMMIT_TYPE_USER_TYPED_WORD is used when the word committed is the exact typed word, with - // no hinting from the IME. It happens when some external event happens (rotating the device, - // for example) or when auto-correction is off by settings or editor attributes. - public static final int COMMIT_TYPE_USER_TYPED_WORD = 0; - // COMMIT_TYPE_MANUAL_PICK is used when the user pressed a field in the suggestion strip. - public static final int COMMIT_TYPE_MANUAL_PICK = 1; - // COMMIT_TYPE_DECIDED_WORD is used when the IME commits the word it decided was best - // for the current user input. It may be different from what the user typed (true auto-correct) - // or it may be exactly what the user typed if it's in the dictionary or the IME does not have - // enough confidence in any suggestion to auto-correct (auto-correct to typed word). - public static final int COMMIT_TYPE_DECIDED_WORD = 2; - // COMMIT_TYPE_CANCEL_AUTO_CORRECT is used upon committing back the old word upon cancelling - // an auto-correction. - public static final int COMMIT_TYPE_CANCEL_AUTO_CORRECT = 3; - - // Storage for all the info about the current input. - private static class CharacterStore { - /** - * The list of unicode values for each keystroke (including surrounding keys) - */ - ArrayList<int[]> mCodes; - int[] mXCoordinates; - int[] mYCoordinates; - StringBuilder mTypedWord; - CharSequence mAutoCorrection; - CharacterStore() { - final int N = BinaryDictionary.MAX_WORD_LENGTH; - mCodes = new ArrayList<int[]>(N); - mTypedWord = new StringBuilder(N); - mXCoordinates = new int[N]; - mYCoordinates = new int[N]; - mAutoCorrection = null; - } - CharacterStore(final CharacterStore that) { - mCodes = new ArrayList<int[]>(that.mCodes); - mTypedWord = new StringBuilder(that.mTypedWord); - mXCoordinates = Arrays.copyOf(that.mXCoordinates, that.mXCoordinates.length); - mYCoordinates = Arrays.copyOf(that.mYCoordinates, that.mYCoordinates.length); - } - void reset() { - // For better performance than creating a new character store. - mCodes.clear(); - mTypedWord.setLength(0); - mAutoCorrection = null; - } - } + final int N = BinaryDictionary.MAX_WORD_LENGTH; - // The currently typing word. May not be null. - private CharacterStore mCurrentWord; - // The information being kept for resuming suggestion. May be null if wiped. - private CharacterStore mCommittedWordSavedForSuggestionResuming; + private ArrayList<int[]> mCodes; + private int[] mXCoordinates; + private int[] mYCoordinates; + private StringBuilder mTypedWord; + private CharSequence mAutoCorrection; + // Cache these values for performance private int mCapsCount; - private boolean mAutoCapitalized; - // Cache this value for performance private int mTrailingSingleQuotesCount; /** @@ -99,8 +52,11 @@ public class WordComposer { private boolean mIsFirstCharCapitalized; public WordComposer() { - mCurrentWord = new CharacterStore(); - mCommittedWordSavedForSuggestionResuming = null; + mCodes = new ArrayList<int[]>(N); + mTypedWord = new StringBuilder(N); + mXCoordinates = new int[N]; + mYCoordinates = new int[N]; + mAutoCorrection = null; mTrailingSingleQuotesCount = 0; } @@ -109,8 +65,10 @@ public class WordComposer { } public void init(WordComposer source) { - mCurrentWord = new CharacterStore(source.mCurrentWord); - mCommittedWordSavedForSuggestionResuming = source.mCommittedWordSavedForSuggestionResuming; + mCodes = new ArrayList<int[]>(source.mCodes); + mTypedWord = new StringBuilder(source.mTypedWord); + mXCoordinates = Arrays.copyOf(source.mXCoordinates, source.mXCoordinates.length); + mYCoordinates = Arrays.copyOf(source.mYCoordinates, source.mYCoordinates.length); mCapsCount = source.mCapsCount; mIsFirstCharCapitalized = source.mIsFirstCharCapitalized; mAutoCapitalized = source.mAutoCapitalized; @@ -121,8 +79,9 @@ public class WordComposer { * Clear out the keys registered so far. */ public void reset() { - mCurrentWord.reset(); - mCommittedWordSavedForSuggestionResuming = null; + mCodes.clear(); + mTypedWord.setLength(0); + mAutoCorrection = null; mCapsCount = 0; mIsFirstCharCapitalized = false; mTrailingSingleQuotesCount = 0; @@ -133,7 +92,7 @@ public class WordComposer { * @return the number of keystrokes */ public final int size() { - return mCurrentWord.mTypedWord.length(); + return mTypedWord.length(); } public final boolean isComposingWord() { @@ -146,15 +105,15 @@ public class WordComposer { * @return the unicode for the pressed and surrounding keys */ public int[] getCodesAt(int index) { - return mCurrentWord.mCodes.get(index); + return mCodes.get(index); } public int[] getXCoordinates() { - return mCurrentWord.mXCoordinates; + return mXCoordinates; } public int[] getYCoordinates() { - return mCurrentWord.mYCoordinates; + return mYCoordinates; } private static boolean isFirstCharCapitalized(int index, int codePoint, boolean previous) { @@ -169,12 +128,12 @@ public class WordComposer { */ public void add(int primaryCode, int[] codes, int x, int y) { final int newIndex = size(); - mCurrentWord.mTypedWord.append((char) primaryCode); + mTypedWord.append((char) primaryCode); correctPrimaryJuxtapos(primaryCode, codes); - mCurrentWord.mCodes.add(codes); + mCodes.add(codes); if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { - mCurrentWord.mXCoordinates[newIndex] = x; - mCurrentWord.mYCoordinates[newIndex] = y; + mXCoordinates[newIndex] = x; + mYCoordinates[newIndex] = y; } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); @@ -184,7 +143,7 @@ public class WordComposer { } else { mTrailingSingleQuotesCount = 0; } - mCurrentWord.mAutoCorrection = null; + mAutoCorrection = null; } /** @@ -218,7 +177,6 @@ public class WordComposer { int codePoint = word.charAt(i); addKeyInfo(codePoint, keyboard, keyDetector); } - mCommittedWordSavedForSuggestionResuming = null; } /** @@ -254,9 +212,9 @@ public class WordComposer { final int size = size(); if (size > 0) { final int lastPos = size - 1; - char lastChar = mCurrentWord.mTypedWord.charAt(lastPos); - mCurrentWord.mCodes.remove(lastPos); - mCurrentWord.mTypedWord.deleteCharAt(lastPos); + char lastChar = mTypedWord.charAt(lastPos); + mCodes.remove(lastPos); + mTypedWord.deleteCharAt(lastPos); if (Character.isUpperCase(lastChar)) mCapsCount--; } if (size() == 0) { @@ -265,12 +223,12 @@ public class WordComposer { if (mTrailingSingleQuotesCount > 0) { --mTrailingSingleQuotesCount; } else { - for (int i = mCurrentWord.mTypedWord.length() - 1; i >= 0; --i) { - if (Keyboard.CODE_SINGLE_QUOTE != mCurrentWord.mTypedWord.codePointAt(i)) break; + for (int i = mTypedWord.length() - 1; i >= 0; --i) { + if (Keyboard.CODE_SINGLE_QUOTE != mTypedWord.codePointAt(i)) break; ++mTrailingSingleQuotesCount; } } - mCurrentWord.mAutoCorrection = null; + mAutoCorrection = null; } /** @@ -278,7 +236,7 @@ public class WordComposer { * @return the word that was typed so far. Never returns null. */ public String getTypedWord() { - return mCurrentWord.mTypedWord.toString(); + return mTypedWord.toString(); } /** @@ -329,26 +287,18 @@ public class WordComposer { * Sets the auto-correction for this word. */ public void setAutoCorrection(final CharSequence correction) { - mCurrentWord.mAutoCorrection = correction; - } - - /** - * Remove any auto-correction that may have been set. - */ - public void deleteAutoCorrection() { - mCurrentWord.mAutoCorrection = null; + mAutoCorrection = correction; } /** * @return the auto-correction for this word, or null if none. */ public CharSequence getAutoCorrectionOrNull() { - return mCurrentWord.mAutoCorrection; + return mAutoCorrection; } - // `type' should be one of the COMMIT_TYPE_* constants above. - public void onCommitWord(final int type) { - mCommittedWordSavedForSuggestionResuming = mCurrentWord; + // `type' should be one of the LastComposedWord.COMMIT_TYPE_* constants above. + public LastComposedWord commitWord(final int type) { // Note: currently, we come here whenever we commit a word. If it's any *other* kind than // DECIDED_WORD, we should reset mAutoCorrection so that we don't attempt to cancel later. // If it's a DECIDED_WORD, it may be an actual auto-correction by the IME, or what the user @@ -356,30 +306,25 @@ public class WordComposer { // Ideally we would also null it when it was a DECIDED_WORD that was not an auto-correct. // As it happens these two cases should behave differently, because the former can be // canceled while the latter can't. Currently, we figure this out in - // #didAutoCorrectToAnotherWord with #equals(). It would be marginally cleaner to do it - // here, but it would be slower (since we would #equals() for each commit, instead of - // only on cancel), and ultimately we want to figure it out even earlier anyway. - if (type != COMMIT_TYPE_DECIDED_WORD) { - // Only ever revert an auto-correct. - mCommittedWordSavedForSuggestionResuming.mAutoCorrection = null; - } - // TODO: improve performance by swapping buffers instead of creating a new object. - mCurrentWord = new CharacterStore(); - } - - public boolean hasWordKeptForSuggestionResuming() { - return null != mCommittedWordSavedForSuggestionResuming; - } - - public void resumeSuggestionOnKeptWord() { - mCurrentWord = mCommittedWordSavedForSuggestionResuming; - mCommittedWordSavedForSuggestionResuming = null; + // LastComposedWord#didAutoCorrectToAnotherWord with #equals(). It would be marginally + // cleaner to do it here, but it would be slower (since we would #equals() for each commit, + // instead of only on cancel), and ultimately we want to figure it out even earlier anyway. + final LastComposedWord lastComposedWord = new LastComposedWord(mCodes, + mXCoordinates, mYCoordinates, mTypedWord.toString(), + (type != LastComposedWord.COMMIT_TYPE_DECIDED_WORD) || (null == mAutoCorrection) + ? null : mAutoCorrection.toString()); + mCodes.clear(); + mTypedWord.setLength(0); + mAutoCorrection = null; + return lastComposedWord; } - public boolean didAutoCorrectToAnotherWord() { - return null != mCommittedWordSavedForSuggestionResuming - && !TextUtils.isEmpty(mCommittedWordSavedForSuggestionResuming.mAutoCorrection) - && !TextUtils.equals(mCommittedWordSavedForSuggestionResuming.mTypedWord, - mCommittedWordSavedForSuggestionResuming.mAutoCorrection); + public void resumeSuggestionOnLastComposedWord(final LastComposedWord lastComposedWord) { + mCodes = lastComposedWord.mCodes; + mXCoordinates = lastComposedWord.mXCoordinates; + mYCoordinates = lastComposedWord.mYCoordinates; + mTypedWord.setLength(0); + mTypedWord.append(lastComposedWord.mTypedWord); + mAutoCorrection = lastComposedWord.mAutoCorrection; } } diff --git a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java index 39e47f661..88ac043ed 100644 --- a/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java +++ b/java/src/com/android/inputmethod/latin/spellcheck/AndroidSpellCheckerService.java @@ -31,7 +31,6 @@ import com.android.inputmethod.compat.SuggestionsInfoCompatUtils; import com.android.inputmethod.keyboard.ProximityInfo; import com.android.inputmethod.latin.BinaryDictionary; import com.android.inputmethod.latin.Dictionary; -import com.android.inputmethod.latin.Dictionary.DataType; import com.android.inputmethod.latin.Dictionary.WordCallback; import com.android.inputmethod.latin.DictionaryCollection; import com.android.inputmethod.latin.DictionaryFactory; @@ -237,7 +236,7 @@ public class AndroidSpellCheckerService extends SpellCheckerService @Override synchronized public boolean addWord(char[] word, int wordOffset, int wordLength, int score, - int dicTypeId, DataType dataType) { + int dicTypeId, int dataType) { final int positionIndex = ArraysCompatUtils.binarySearch(mScores, 0, mLength, score); // binarySearch returns the index if the element exists, and -<insertion index> - 1 // if it doesn't. See documentation for binarySearch. |