From eea34598bf63f670f47d7b3f37b6436921e5fe02 Mon Sep 17 00:00:00 2001 From: Tom Ouyang Date: Tue, 12 Jun 2012 03:40:37 -0700 Subject: [PATCH 1/9] Merging minimal gesture input Change-Id: Iee6ae48bb6309c2867b5d2e344fe7d86dfabd654 --- .../keyboard/KeyboardActionListener.java | 14 +- .../inputmethod/keyboard/PointerTracker.java | 91 ++++- .../keyboard/internal/GestureTracker.java | 325 ++++++++++++++++++ .../internal/PointerTrackerQueue.java | 4 + .../android/inputmethod/latin/LatinIME.java | 37 +- .../android/inputmethod/latin/Suggest.java | 18 +- .../inputmethod/latin/WordComposer.java | 26 +- 7 files changed, 483 insertions(+), 32 deletions(-) create mode 100644 java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java index dc27769ab..1f3ee7680 100644 --- a/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java +++ b/java/src/com/android/inputmethod/keyboard/KeyboardActionListener.java @@ -16,6 +16,9 @@ package com.android.inputmethod.keyboard; +import com.android.inputmethod.latin.InputPointers; +import com.android.inputmethod.latin.SuggestedWords; + public interface KeyboardActionListener { /** @@ -64,13 +67,18 @@ public interface KeyboardActionListener { */ public void onTextInput(CharSequence text); - // TODO: Should move this method to some more appropriate interface. /** * Called when user started batch input. */ public void onStartBatchInput(); - // TODO: Should move this method to some more appropriate interface. + /** + * Sends the batch input points data to get updated suggestions + * @param batchPointers the batch input points representing the user input + * @return updated suggestions that reflects the user input + */ + public SuggestedWords onUpdateBatchInput(InputPointers batchPointers); + /** * Sends a sequence of characters to the listener as batch input. * @@ -101,6 +109,8 @@ public interface KeyboardActionListener { @Override public void onStartBatchInput() {} @Override + public SuggestedWords onUpdateBatchInput(InputPointers batchPointers) { return null; } + @Override public void onEndBatchInput(CharSequence text) {} @Override public void onCancelInput() {} diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java index 1ae0020a4..733d3b09b 100644 --- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java +++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java @@ -22,6 +22,7 @@ import android.view.MotionEvent; import android.view.View; import android.widget.TextView; +import com.android.inputmethod.keyboard.internal.GestureTracker; import com.android.inputmethod.keyboard.internal.PointerTrackerQueue; import com.android.inputmethod.latin.LatinImeLogger; import com.android.inputmethod.latin.ResearchLogger; @@ -161,6 +162,9 @@ public class PointerTracker { private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener.Adapter(); + // Gesture tracker singleton instance + private static final GestureTracker sGestureTracker = GestureTracker.getInstance(); + public static void init(boolean hasDistinctMultitouch, boolean needsPhantomSuddenMoveEventHack) { if (hasDistinctMultitouch) { @@ -199,6 +203,7 @@ public class PointerTracker { for (final PointerTracker tracker : sTrackers) { tracker.mListener = listener; } + GestureTracker.init(listener); } public static void setKeyDetector(KeyDetector keyDetector) { @@ -207,6 +212,7 @@ public class PointerTracker { // Mark that keyboard layout has been changed. tracker.mKeyboardLayoutHasBeenChanged = true; } + sGestureTracker.setKeyboard(keyDetector.getKeyboard()); } public static void dismissAllKeyPreviews() { @@ -233,6 +239,9 @@ public class PointerTracker { // Returns true if keyboard has been changed by this callback. private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) { + if (sGestureTracker.isInGesture()) { + return false; + } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onPress : " + KeyDetector.printableCode(key) @@ -286,6 +295,9 @@ public class PointerTracker { // Note that we need primaryCode argument because the keyboard may in shifted state and the // primaryCode is different from {@link Key#mCode}. private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { + if (sGestureTracker.isInGesture()) { + return; + } final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier(); if (DEBUG_LISTENER) { Log.d(TAG, "onRelease : " + Keyboard.printableCode(primaryCode) @@ -386,7 +398,7 @@ public class PointerTracker { return; } - if (!key.noKeyPreview()) { + if (!key.noKeyPreview() && !sGestureTracker.isInGesture()) { mDrawingProxy.showKeyPreview(this); } updatePressKeyGraphics(key); @@ -504,8 +516,8 @@ public class PointerTracker { } final PointerTrackerQueue queue = sPointerTrackerQueue; + final Key key = getKeyOn(x, y); if (queue != null) { - final Key key = getKeyOn(x, y); if (key != null && key.isModifier()) { // Before processing a down event of modifier key, all pointers already being // tracked should be released. @@ -514,6 +526,9 @@ public class PointerTracker { queue.add(this); } onDownEventInternal(x, y, eventTime); + if (queue != null && queue.size() == 1) { + sGestureTracker.onDownEvent(this, x, y, eventTime, key); + } } private void onDownEventInternal(int x, int y, long eventTime) { @@ -554,10 +569,34 @@ public class PointerTracker { if (mKeyAlreadyProcessed) return; + if (me != null) { + // Add historical points to gesture path. + final int pointerIndex = me.findPointerIndex(mPointerId); + final int historicalSize = me.getHistorySize(); + for (int h = 0; h < historicalSize; h++) { + final int historicalX = (int)me.getHistoricalX(pointerIndex, h); + final int historicalY = (int)me.getHistoricalY(pointerIndex, h); + final long historicalTime = me.getHistoricalEventTime(h); + sGestureTracker.onMoveEvent(this, historicalX, historicalY, historicalTime, + true /* isHistorical */, null); + } + } + final int lastX = mLastX; final int lastY = mLastY; final Key oldKey = mCurrentKey; Key key = onMoveKey(x, y); + + // Register move event on gesture tracker. + sGestureTracker.onMoveEvent(this, x, y, eventTime, false, key); + if (sGestureTracker.isInGesture()) { + mIgnoreModifierKey = true; + mTimerProxy.cancelLongPressTimer(); + mIsInSlidingKeyInput = true; + mCurrentKey = null; + setReleasedKeyGraphics(oldKey); + } + if (key != null) { if (oldKey == null) { // The pointer has been slid in to the new key, but the finger was not on any keys. @@ -607,7 +646,7 @@ public class PointerTracker { if (ProductionFlag.IS_EXPERIMENTAL) { ResearchLogger.pointerTracker_onMoveEvent(x, y, lastX, lastY); } - onUpEventInternal(); + onUpEventInternal(x, y, eventTime); onDownEventInternal(x, y, eventTime); } else { // HACK: If there are currently multiple touches, register the key even if @@ -617,7 +656,7 @@ public class PointerTracker { // this hack. if (me != null && me.getPointerCount() > 1 && !sPointerTrackerQueue.hasModifierKeyOlderThan(this)) { - onUpEventInternal(); + onUpEventInternal(x, y, eventTime); } mKeyAlreadyProcessed = true; setReleasedKeyGraphics(oldKey); @@ -647,16 +686,18 @@ public class PointerTracker { final PointerTrackerQueue queue = sPointerTrackerQueue; if (queue != null) { - if (mCurrentKey != null && mCurrentKey.isModifier()) { - // Before processing an up event of modifier key, all pointers already being - // tracked should be released. - queue.releaseAllPointersExcept(this, eventTime); - } else { - queue.releaseAllPointersOlderThan(this, eventTime); + if (!sGestureTracker.isInGesture()) { + if (mCurrentKey != null && mCurrentKey.isModifier()) { + // Before processing an up event of modifier key, all pointers already being + // tracked should be released. + queue.releaseAllPointersExcept(this, eventTime); + } else { + queue.releaseAllPointersOlderThan(this, eventTime); + } } queue.remove(this); } - onUpEventInternal(); + onUpEventInternal(x, y, eventTime); } // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. @@ -665,11 +706,11 @@ public class PointerTracker { public void onPhantomUpEvent(int x, int y, long eventTime) { if (DEBUG_EVENT) printTouchEvent("onPhntEvent:", x, y, eventTime); - onUpEventInternal(); + onUpEventInternal(x, y, eventTime); mKeyAlreadyProcessed = true; } - private void onUpEventInternal() { + private void onUpEventInternal(int x, int y, long eventTime) { mTimerProxy.cancelKeyTimers(); mIsInSlidingKeyInput = false; // Release the last pressed key. @@ -678,6 +719,24 @@ public class PointerTracker { mDrawingProxy.dismissMoreKeysPanel(); mIsShowingMoreKeysPanel = false; } + + if (sGestureTracker.isInGesture()) { + // Register up event on gesture tracker. + sGestureTracker.onUpEvent(this, x, y, eventTime); + if (!sPointerTrackerQueue.isAnyInSlidingKeyInput()) { + // TODO: Calls to beginBatchInput() is missing in this class. Reorganize the code. + sGestureTracker.endBatchInput(); + } + if (mCurrentKey != null) { + callListenerOnRelease(mCurrentKey, mCurrentKey.mCode, true); + } + mCurrentKey = null; + return; + } else { + // TODO: Calls to beginBatchInput() is missing in this class. Reorganize the code. + sGestureTracker.endBatchInput(); + } + if (mKeyAlreadyProcessed) return; if (mCurrentKey != null && !mCurrentKey.isRepeatable()) { @@ -689,6 +748,8 @@ public class PointerTracker { onLongPressed(); onDownEvent(x, y, SystemClock.uptimeMillis(), handler); mIsShowingMoreKeysPanel = true; + // TODO: Calls to beginBatchInput() is missing in this class. Reorganize the code. + sGestureTracker.abortBatchInput(); } public void onLongPressed() { @@ -723,7 +784,7 @@ public class PointerTracker { } private void startRepeatKey(Key key) { - if (key != null && key.isRepeatable()) { + if (key != null && key.isRepeatable() && !sGestureTracker.isInGesture()) { onRegisterKey(key); mTimerProxy.startKeyRepeatTimer(this); } @@ -753,7 +814,7 @@ public class PointerTracker { } private void startLongPressTimer(Key key) { - if (key != null && key.isLongPressEnabled()) { + if (key != null && key.isLongPressEnabled() && !sGestureTracker.isInGesture()) { mTimerProxy.startLongPressTimer(this); } } diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java new file mode 100644 index 000000000..f98911445 --- /dev/null +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java @@ -0,0 +1,325 @@ +/* + * 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.keyboard.internal; + +import android.util.Log; +import android.util.SparseArray; + +import com.android.inputmethod.keyboard.Key; +import com.android.inputmethod.keyboard.Keyboard; +import com.android.inputmethod.keyboard.KeyboardActionListener; +import com.android.inputmethod.keyboard.PointerTracker; +import com.android.inputmethod.latin.InputPointers; +import com.android.inputmethod.latin.SuggestedWords; + +// TODO: Remove this class by consolidating with PointerTracker +public class GestureTracker { + private static final String TAG = GestureTracker.class.getSimpleName(); + private static final boolean DEBUG_LISTENER = false; + + // TODO: There should be an option to turn on/off the gesture input. + private static final boolean GESTURE_ON = true; + + private static final GestureTracker sInstance = new GestureTracker(); + + private static final int MIN_RECOGNITION_TIME = 100; + private static final int MIN_GESTURE_DURATION = 200; + + private static final float GESTURE_RECOG_SPEED_THRESHOLD = 0.4f; + private static final float SQUARED_GESTURE_RECOG_SPEED_THRESHOLD = + GESTURE_RECOG_SPEED_THRESHOLD * GESTURE_RECOG_SPEED_THRESHOLD; + private static final float GESTURE_RECOG_CURVATURE_THRESHOLD = (float) (Math.PI / 4); + + private boolean mIsAlphabetKeyboard; + private boolean mIsPossibleGesture = false; + private boolean mInGesture = false; + + private KeyboardActionListener mListener; + private SuggestedWords mSuggestions; + + private final SparseArray mGestureStrokes = new SparseArray(); + + private int mLastRecognitionPointSize = 0; + private long mLastRecognitionTime = 0; + + public static void init(KeyboardActionListener listner) { + sInstance.mListener = listner; + } + + public static GestureTracker getInstance() { + return sInstance; + } + + private GestureTracker() { + } + + public void setKeyboard(Keyboard keyboard) { + mIsAlphabetKeyboard = keyboard.mId.isAlphabetKeyboard(); + GestureStroke.setGestureSampleLength(keyboard.mMostCommonKeyWidth / 2, + keyboard.mMostCommonKeyHeight / 6); + } + + private void startBatchInput() { + if (DEBUG_LISTENER) { + Log.d(TAG, "onStartBatchInput"); + } + mInGesture = true; + mListener.onStartBatchInput(); + mSuggestions = null; + } + + // TODO: The corresponding startBatchInput() is a private method. Reorganize the code. + public void endBatchInput() { + if (isInGesture() && mSuggestions != null && mSuggestions.size() > 0) { + final CharSequence text = mSuggestions.getWord(0); + if (DEBUG_LISTENER) { + Log.d(TAG, "onEndBatchInput: text=" + text); + } + mListener.onEndBatchInput(text); + } + mInGesture = false; + clearBatchInputPoints(); + } + + public void abortBatchInput() { + mIsPossibleGesture = false; + mInGesture = false; + } + + public boolean isInGesture() { + return mInGesture; + } + + public void onDownEvent(PointerTracker tracker, int x, int y, long eventTime, Key key) { + mIsPossibleGesture = false; + if (GESTURE_ON && mIsAlphabetKeyboard && key != null && !key.isModifier()) { + mIsPossibleGesture = true; + addPointToStroke(x, y, 0, tracker.mPointerId, false); + } + } + + public void onMoveEvent(PointerTracker tracker, int x, int y, long eventTime, + boolean isHistorical, Key key) { + final int gestureTime = (int)(eventTime - tracker.getDownTime()); + if (GESTURE_ON && mIsPossibleGesture) { + final GestureStroke stroke = addPointToStroke(x, y, gestureTime, tracker.mPointerId, + isHistorical); + if (!isInGesture() && stroke.isStartOfAGesture(gestureTime)) { + startBatchInput(); + } + } + + if (key != null && isInGesture()) { + final InputPointers batchPoints = getIncrementalBatchPoints(); + if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) { + if (DEBUG_LISTENER) { + Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize()); + } + mSuggestions = mListener.onUpdateBatchInput(batchPoints); + } + } + } + + public void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) { + if (isInGesture()) { + final InputPointers batchPoints = getAllBatchPoints(); + if (DEBUG_LISTENER) { + Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize()); + } + mSuggestions = mListener.onUpdateBatchInput(batchPoints); + } + } + + private GestureStroke addPointToStroke(int x, int y, int time, int pointerId, + boolean isHistorical) { + GestureStroke stroke = mGestureStrokes.get(pointerId); + if (stroke == null) { + stroke = new GestureStroke(pointerId); + mGestureStrokes.put(pointerId, stroke); + } + stroke.addPoint(x, y, time, isHistorical); + return stroke; + } + + // The working and return object of the following methods, {@link #getIncrementalBatchPoints()} + // and {@link #getAllBatchPoints()}. + private final InputPointers mAggregatedPointers = new InputPointers(); + + private InputPointers getIncrementalBatchPoints() { + final InputPointers pointers = mAggregatedPointers; + pointers.reset(); + final int strokeSize = mGestureStrokes.size(); + for (int index = 0; index < strokeSize; index++) { + final GestureStroke stroke = mGestureStrokes.valueAt(index); + stroke.appendIncrementalBatchPoints(pointers); + } + return pointers; + } + + private InputPointers getAllBatchPoints() { + final InputPointers pointers = mAggregatedPointers; + pointers.reset(); + final int strokeSize = mGestureStrokes.size(); + for (int index = 0; index < strokeSize; index++) { + final GestureStroke stroke = mGestureStrokes.valueAt(index); + stroke.appendAllBatchPoints(pointers); + } + return pointers; + } + + private void clearBatchInputPoints() { + final int strokeSize = mGestureStrokes.size(); + for (int index = 0; index < strokeSize; index++) { + final GestureStroke stroke = mGestureStrokes.valueAt(index); + stroke.reset(); + } + mLastRecognitionPointSize = 0; + mLastRecognitionTime = 0; + } + + private boolean updateBatchInputRecognitionState(long eventTime, int size) { + if (size > mLastRecognitionPointSize + && eventTime > mLastRecognitionTime + MIN_RECOGNITION_TIME) { + mLastRecognitionPointSize = size; + mLastRecognitionTime = eventTime; + return true; + } + return false; + } + + private static class GestureStroke { + private final int mPointerId; + private final InputPointers mInputPointers = new InputPointers(); + private float mLength; + private float mAngle; + private int mIncrementalRecognitionPoint; + private boolean mHasSharpCorner; + private long mLastPointTime; + private int mLastPointX; + private int mLastPointY; + + private static int sMinGestureLength; + private static int sSquaredGestureSampleLength; + + private static final float DOUBLE_PI = (float)(2 * Math.PI); + + public static void setGestureSampleLength(final int minGestureLength, + final int sampleLength) { + sMinGestureLength = minGestureLength; + sSquaredGestureSampleLength = sampleLength * sampleLength; + } + + public GestureStroke(int pointerId) { + mPointerId = pointerId; + reset(); + } + + public boolean isStartOfAGesture(int downDuration) { + return downDuration > MIN_GESTURE_DURATION / 2 && mLength > sMinGestureLength / 2; + } + + public void reset() { + mLength = 0; + mAngle = 0; + mIncrementalRecognitionPoint = 0; + mHasSharpCorner = false; + mLastPointTime = 0; + mInputPointers.reset(); + } + + private void updateLastPoint(final int x, final int y, final int time) { + mLastPointTime = time; + mLastPointX = x; + mLastPointY = y; + } + + public void addPoint(final int x, final int y, final int time, final boolean isHistorical) { + final int size = mInputPointers.getPointerSize(); + if (size == 0) { + mInputPointers.addPointer(x, y, mPointerId, time); + if (!isHistorical) { + updateLastPoint(x, y, time); + } + return; + } + + final int[] xCoords = mInputPointers.getXCoordinates(); + final int[] yCoords = mInputPointers.getYCoordinates(); + final int lastX = xCoords[size - 1]; + final int lastY = yCoords[size - 1]; + final float dist = squaredDistance(lastX, lastY, x, y); + if (dist > sSquaredGestureSampleLength) { + mInputPointers.addPointer(x, y, mPointerId, time); + mLength += dist; + final float angle = angle(lastX, lastY, x, y); + if (size > 1) { + float curvature = getAngleDiff(angle, mAngle); + if (curvature > GESTURE_RECOG_CURVATURE_THRESHOLD) { + if (size > mIncrementalRecognitionPoint) { + mIncrementalRecognitionPoint = size; + } + mHasSharpCorner = true; + } + if (!mHasSharpCorner) { + mIncrementalRecognitionPoint = size; + } + } + mAngle = angle; + } + + if (!isHistorical) { + final int duration = (int)(time - mLastPointTime); + if (mLastPointTime != 0 && duration > 0) { + final int squaredDuration = duration * duration; + final float squaredSpeed = + squaredDistance(mLastPointX, mLastPointY, x, y) / squaredDuration; + if (squaredSpeed < SQUARED_GESTURE_RECOG_SPEED_THRESHOLD) { + mIncrementalRecognitionPoint = size; + } + } + updateLastPoint(x, y, time); + } + } + + private float getAngleDiff(float a1, float a2) { + final float diff = Math.abs(a1 - a2); + if (diff > Math.PI) { + return DOUBLE_PI - diff; + } + return diff; + } + + public void appendAllBatchPoints(InputPointers out) { + out.append(mInputPointers, 0, mInputPointers.getPointerSize()); + } + + public void appendIncrementalBatchPoints(InputPointers out) { + out.append(mInputPointers, 0, mIncrementalRecognitionPoint); + } + } + + static float squaredDistance(int p1x, int p1y, int p2x, int p2y) { + final float dx = p1x - p2x; + final float dy = p1y - p2y; + return dx * dx + dy * dy; + } + + static float angle(int p1x, int p1y, int p2x, int p2y) { + final int dx = p1x - p2x; + final int dy = p1y - p2y; + if (dx == 0 && dy == 0) return 0; + return (float)Math.atan2(dy, dx); + } +} diff --git a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java index d3bb85d4b..e4a71844a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java +++ b/java/src/com/android/inputmethod/keyboard/internal/PointerTrackerQueue.java @@ -31,6 +31,10 @@ public class PointerTrackerQueue { // TODO: Use ring buffer instead of {@link LinkedList}. private final LinkedList mQueue = new LinkedList(); + public int size() { + return mQueue.size(); + } + public synchronized void add(PointerTracker tracker) { mQueue.add(tracker); } diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index f27d32150..518bcd5ce 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -1268,13 +1268,16 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (SPACE_STATE_PHANTOM == spaceState) { commitTyped(LastComposedWord.NOT_A_SEPARATOR); } + final int keyX, keyY; final Keyboard keyboard = mKeyboardSwitcher.getKeyboard(); if (keyboard != null && keyboard.hasProximityCharsCorrection(primaryCode)) { - handleCharacter(primaryCode, x, y, spaceState); + keyX = x; + keyY = y; } else { - handleCharacter(primaryCode, NOT_A_TOUCH_COORDINATE, NOT_A_TOUCH_COORDINATE, - spaceState); + keyX = NOT_A_TOUCH_COORDINATE; + keyY = NOT_A_TOUCH_COORDINATE; } + handleCharacter(primaryCode, keyX, keyY, spaceState); } mExpectingUpdateSelection = true; mShouldSwitchToLastSubtype = true; @@ -1320,10 +1323,20 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen mSpaceState = SPACE_STATE_PHANTOM; } mConnection.endBatchEdit(); + // TODO: Should handle TextUtils.CAP_MODE_CHARACTER. + mWordComposer.setAutoCapitalized( + getCurrentAutoCapsState() != Constants.TextUtils.CAP_MODE_OFF); + } + + @Override + public SuggestedWords onUpdateBatchInput(InputPointers batchPointers) { + mWordComposer.setBatchInputPointers(batchPointers); + return updateSuggestionsOrPredictions(); } @Override public void onEndBatchInput(CharSequence text) { + mWordComposer.setBatchInputWord(text); mConnection.beginBatchEdit(); if (SPACE_STATE_PHANTOM == mSpaceState) { sendKeyCodePoint(Keyboard.CODE_SPACE); @@ -1669,7 +1682,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } // TODO: rename this method to updateSuggestionStrip or simply updateSuggestions - private void updateSuggestionsOrPredictions() { + private SuggestedWords updateSuggestionsOrPredictions() { mHandler.cancelUpdateSuggestionStrip(); // Check if we have a suggestion engine attached. @@ -1679,13 +1692,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen + "requested!"); mWordComposer.setAutoCorrection(mWordComposer.getTypedWord()); } - return; + return null; } final String typedWord = mWordComposer.getTypedWord(); if (!mWordComposer.isComposingWord() && !mCurrentSettings.mBigramPredictionEnabled) { setPunctuationSuggestions(); - return; + return null; } // Get the word on which we should search the bigrams. If we are composing a word, it's @@ -1701,6 +1714,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen suggestedWords = maybeRetrieveOlderSuggestions(typedWord, suggestedWords); showSuggestions(suggestedWords, typedWord); + return suggestedWords; } private SuggestedWords maybeRetrieveOlderSuggestions(final CharSequence typedWord, @@ -1761,9 +1775,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen if (mHandler.hasPendingUpdateSuggestions()) { updateSuggestionsOrPredictions(); } - final CharSequence autoCorrection = mWordComposer.getAutoCorrectionOrNull(); + final CharSequence typedAutoCorrection = mWordComposer.getAutoCorrectionOrNull(); + final String typedWord = mWordComposer.getTypedWord(); + final CharSequence autoCorrection = (typedAutoCorrection != null) + ? typedAutoCorrection : typedWord; if (autoCorrection != null) { - final String typedWord = mWordComposer.getTypedWord(); if (TextUtils.isEmpty(typedWord)) { throw new RuntimeException("We have an auto-correction but the typed word " + "is empty? Impossible! I must commit suicide."); @@ -1808,7 +1824,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen } mConnection.beginBatchEdit(); - if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0) { + if (SPACE_STATE_PHANTOM == mSpaceState && suggestion.length() > 0 + // In the batch input mode, a manually picked suggested word should just replace + // the current batch input text and there is no need for a phantom space. + && !mWordComposer.isBatchMode()) { int firstChar = Character.codePointAt(suggestion, 0); if ((!mCurrentSettings.isWeakSpaceStripper(firstChar)) && (!mCurrentSettings.isWeakSpaceSwapper(firstChar))) { diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java index 31566bf13..598ef1de7 100644 --- a/java/src/com/android/inputmethod/latin/Suggest.java +++ b/java/src/com/android/inputmethod/latin/Suggest.java @@ -300,11 +300,27 @@ public class Suggest { final ArrayList suggestionsContainer = new ArrayList(suggestionsSet); + final int suggestionsCount = suggestionsContainer.size(); + final boolean isFirstCharCapitalized = wordComposer.isAutoCapitalized(); + // TODO: Handle the manual temporary shifted mode. + // TODO: Should handle TextUtils.CAP_MODE_CHARACTER. + final boolean isAllUpperCase = false; + if (isFirstCharCapitalized || isAllUpperCase) { + for (int i = 0; i < suggestionsCount; ++i) { + final SuggestedWordInfo wordInfo = suggestionsContainer.get(i); + final SuggestedWordInfo transformedWordInfo = getTransformedSuggestedWordInfo( + wordInfo, mLocale, isAllUpperCase, isFirstCharCapitalized, + 0 /* trailingSingleQuotesCount */); + suggestionsContainer.set(i, transformedWordInfo); + } + } SuggestedWordInfo.removeDups(suggestionsContainer); + // In the batch input mode, the most relevant suggested word should act as a "typed word" + // (typedWordValid=true), not as an "auto correct word" (willAutoCorrect=false). return new SuggestedWords(suggestionsContainer, true /* typedWordValid */, - true /* willAutoCorrect */, + false /* willAutoCorrect */, false /* isPunctuationSuggestions */, false /* isObsoleteSuggestions */, false /* isPrediction */); diff --git a/java/src/com/android/inputmethod/latin/WordComposer.java b/java/src/com/android/inputmethod/latin/WordComposer.java index 25e29008e..ca9dbaf05 100644 --- a/java/src/com/android/inputmethod/latin/WordComposer.java +++ b/java/src/com/android/inputmethod/latin/WordComposer.java @@ -130,8 +130,13 @@ public class WordComposer { if (newIndex < BinaryDictionary.MAX_WORD_LENGTH) { mPrimaryKeyCodes[newIndex] = primaryCode >= Keyboard.CODE_SPACE ? Character.toLowerCase(primaryCode) : primaryCode; - // TODO: Set correct pointer id and time - mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); + // In the batch input mode, the {@code mInputPointers} holds batch input points and + // shouldn't be overridden by the "typed key" coordinates + // (See {@link #setBatchInputWord}). + if (!mIsBatchMode) { + // TODO: Set correct pointer id and time + mInputPointers.addPointer(newIndex, keyX, keyY, 0, 0); + } } mIsFirstCharCapitalized = isFirstCharCapitalized( newIndex, primaryCode, mIsFirstCharCapitalized); @@ -144,12 +149,23 @@ public class WordComposer { mAutoCorrection = null; } - // TODO: We may want to have appendBatchInputPointers() as well. public void setBatchInputPointers(InputPointers batchPointers) { - mInputPointers.copy(batchPointers); + mInputPointers.set(batchPointers); mIsBatchMode = true; } + public void setBatchInputWord(CharSequence word) { + reset(); + mIsBatchMode = true; + final int length = word.length(); + for (int i = 0; i < length; i = Character.offsetByCodePoints(word, i, 1)) { + final int codePoint = Character.codePointAt(word, i); + // We don't want to override the batch input points that are held in mInputPointers + // (See {@link #add(int,int,int)}). + add(codePoint, NOT_A_COORDINATE, NOT_A_COORDINATE); + } + } + /** * Internal method to retrieve reasonable proximity info for a character. */ @@ -161,7 +177,7 @@ public class WordComposer { add(codePoint, x, y); return; } - add(codePoint, WordComposer.NOT_A_COORDINATE, WordComposer.NOT_A_COORDINATE); + add(codePoint, NOT_A_COORDINATE, NOT_A_COORDINATE); } /** From 63b12362d6036759e9ccb03a38ceea7946da2fef Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 13 Jul 2012 13:52:11 -0700 Subject: [PATCH 2/9] Import translations. DO NOT MERGE Change-Id: Ibb5bd0c2753e52dc3526ce859b0c108e189a605d Auto-generated-cl: translation import --- java/res/values-af/strings-appname.xml | 3 +-- java/res/values-af/strings.xml | 15 ++++------- java/res/values-am/strings.xml | 2 +- java/res/values-bg/strings.xml | 15 ++++------- java/res/values-fa/strings.xml | 25 ++++++++---------- java/res/values-hi/strings.xml | 15 ++++------- java/res/values-hu/strings.xml | 15 ++++------- java/res/values-in/strings.xml | 8 +++--- java/res/values-ja/strings.xml | 15 ++++------- java/res/values-ko/strings.xml | 15 ++++------- java/res/values-ms/strings-appname.xml | 3 +-- java/res/values-pl/strings-appname.xml | 30 ++++++++++++++++++++++ java/res/values-pl/strings.xml | 15 ++++------- java/res/values-pt/strings-appname.xml | 3 +-- java/res/values-pt/strings.xml | 15 ++++------- java/res/values-ro/strings.xml | 15 ++++------- java/res/values-ru/strings.xml | 15 ++++------- java/res/values-sk/strings.xml | 15 ++++------- java/res/values-th/strings-appname.xml | 9 +++---- java/res/values-th/strings.xml | 15 ++++------- java/res/values-tl/strings.xml | 15 ++++------- java/res/values-tr/strings.xml | 15 ++++------- java/res/values-vi/strings.xml | 15 ++++------- java/res/values-zh-rCN/strings-appname.xml | 3 +-- java/res/values-zh-rTW/strings.xml | 15 ++++------- 25 files changed, 132 insertions(+), 194 deletions(-) create mode 100644 java/res/values-pl/strings-appname.xml diff --git a/java/res/values-af/strings-appname.xml b/java/res/values-af/strings-appname.xml index 1adf723d7..d6bb52f52 100644 --- a/java/res/values-af/strings-appname.xml +++ b/java/res/values-af/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android-sleutelbord" "Android-speltoetser" "Android-sleutelbordinstellings" "Speltoets tans instellings" diff --git a/java/res/values-af/strings.xml b/java/res/values-af/strings.xml index fb7cf349f..65bcaf2e9 100644 --- a/java/res/values-af/strings.xml +++ b/java/res/values-af/strings.xml @@ -107,19 +107,14 @@ "let op die tydstempel in die loglêer" "Aangetekende tydstempel" "Moenie hierdie sessie aanteken nie" - - - - + "Aktiveer sessie-rekordhouding" + "Hou rekord van hele sessiegeskiedenis" "Sessie se loglêer uitgevee" "Sessie se loglêer uitgevee" "Sessie se loglêer NIE uitgevee nie" - - - - - - + "Rekord gehou van sessiegeskiedenis" + "Fout: daar is NIE rekord gehou van die sessiegeskiedenis nie" + "Sessie-rekordhouding geaktiveer" "Invoertale" "Raak weer om te stoor" "Woordeboek beskikbaar" diff --git a/java/res/values-am/strings.xml b/java/res/values-am/strings.xml index d36b9a68b..1f72f05fc 100644 --- a/java/res/values-am/strings.xml +++ b/java/res/values-am/strings.xml @@ -113,7 +113,7 @@ "የክፍለ ጊዜ ምዝግብ ማስታወሻ ተሰርዟል" "የክፍለጊዜ ምዝግብ ማስታወሻ አልተሰረዘም" "የክፍለጊዜ ታሪክ ተመዝግቧል" - "ስህተት፦ክፍለጊዜ ታሪክ አልተመዘገበም" + "ስህተት፦ ክፍለጊዜ ታሪክ አልተመዘገበም" "ክፍለጊዜ ምዝገባ ነቅቷል" "ቋንቋዎች አግቤት" "ለማስቀመጥ እንደገና ንካ" diff --git a/java/res/values-bg/strings.xml b/java/res/values-bg/strings.xml index 38ebfe84a..52c2fc6a8 100644 --- a/java/res/values-bg/strings.xml +++ b/java/res/values-bg/strings.xml @@ -107,19 +107,14 @@ "Отбелязване на часа в рег. файл" "Часът е записан" "Без регистр. на сесията" - - - - + "Записване на сесията: Активиране" + "Цялата история на сесията: Записв." "Рег. файл на сесията се изтрива" "Рег. файл на сесията е изтрит" "Рег. файл на сесията НЕ Е изтрит" - - - - - - + "Историята на сесията е записана" + "Грешка: Ист. на сесията НЕ е записана" + "Записването на сесията е активирано" "Езици за въвеждане" "Докоснете отново, за да запазите" "Има достъп до речник" diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index bfdabab04..1cfac8242 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -25,7 +25,7 @@ "فرمان‌های گزارش‌گیری پژوهش" "غلط‌گیر املای Android (AOSP)" "جستجوی نام مخاطبین" - "غلط‌گیر املا از ورودی‌های لیست مخاطبین شما استفاده میکند" + "غلط‌گیر املا از ورودی‌های لیست مخاطبین شما استفاده می‌کند" "لرزش با فشار کلید" "صدا با فشار کلید" "بازشدن با فشار کلید" @@ -39,10 +39,10 @@ "کلید تغییر زبان را فشار دهید" "تأخیر در رد کردن کلید نمایشی" "بدون تأخیر" - "پیش فرض" - "پیشنهاد نام های مخاطب" + "پیش‌فرض" + "پیشنهاد نام‌های مخاطب" "برای پیشنهاد و تصحیح از نام مخاطبین استفاده شود" - "نوشتن با حروف بزرگ خودکار" + "بزرگ‌کردن خودکار حروف" "فرهنگ‌های لغت افزودنی" "فرهنگ‌ لغت اصلی" "نمایش پیشنهادات تصحیح" @@ -51,7 +51,7 @@ "نمایش در حالت عمودی" "همیشه پنهان شود" "تصحیح خودکار" - "کلید فاصله و علائم نگارشی به صورت خودکار کلماتی را که غلط تایپ شده‌اند تصحیح می کنند" + "کلید فاصله و علائم نگارشی به صورت خودکار کلماتی را که غلط تایپ شده‌اند تصحیح می‌کنند" "خاموش" "متوسط" "فعال" @@ -111,19 +111,14 @@ "یادداشت مهر زمان در گزارش" "مهر زمان ثبت شده" "از این جلسه گزارش‌گیری نشود" - - - - + "تواناساختن گزارش جلسه" + "گزارش همه سابقه جلسه" "در حال حذف گزارش جلسه" "گزارش جلسه حذف شد" "گزارش جلسه حذف نشد" - - - - - - + "سابقه جلسه گزارش شد" + "خطا: سابقه جلسه گزارش نشد" + "گزارش جلسه توانا شد" "زبان‌های ورودی" "برای ذخیره دوباره لمس کنید" "دیکشنری موجود است" diff --git a/java/res/values-hi/strings.xml b/java/res/values-hi/strings.xml index 81fb684bf..dfed256b1 100644 --- a/java/res/values-hi/strings.xml +++ b/java/res/values-hi/strings.xml @@ -107,19 +107,14 @@ "लॉग में टाइमस्‍टैम्‍प नोट करें" "रिकॉर्ड किया गया टाइमस्टैम्प" "इस सत्र को लॉग न करें" - - - - + "सत्र लॉगिंग सक्षम करें" + "संपूर्ण सत्र इतिहास को लॉग करें" "सत्र लॉग हटाया जा रहा है" "सत्र लॉग हटाया गया" "सत्र लॉग हटाया नहीं गया" - - - - - - + "सत्र इतिहास को लॉग लिया गया" + "त्रुटि: सत्र इतिहास लॉग नहीं किया" + "सत्र लॉगिंग सक्षम" "इनपुट भाषाएं" "सहेजने के लिए पुन: स्‍पर्श करें" "शब्‍दकोश उपलब्‍ध है" diff --git a/java/res/values-hu/strings.xml b/java/res/values-hu/strings.xml index a0110e49a..cd9893e62 100644 --- a/java/res/values-hu/strings.xml +++ b/java/res/values-hu/strings.xml @@ -107,19 +107,14 @@ "Időbélyegző naplózáskor" "Rögzített időbélyegzők" "Ne naplózza" - - - - + "Programfolyamat-napló engedélyezése" + "Összes előzmény naplózása" "Napló törlése folyamatban" "Napló törölve" "Napló NINCS törölve" - - - - - - + "Programfolyamatok naplózva" + "Hiba: előzmények NINCSENEK naplózva" + "Naplózás engedélyezve" "Beviteli nyelvek" "Érintse meg újból a mentéshez" "Van elérhető szótár" diff --git a/java/res/values-in/strings.xml b/java/res/values-in/strings.xml index b02656c6e..31c901461 100644 --- a/java/res/values-in/strings.xml +++ b/java/res/values-in/strings.xml @@ -108,13 +108,13 @@ "Cap waktu yang direkam" "Jangan simpan log sesi ini" "Aktifkan log sesi" - "Rekam log seluruh riwayat sesi" + "Catat seluruh riwayat sesi" "Menghapus log sesi" "Log sesi dihapus" "Log sesi BELUM dihapus" - "Log riwayat sesi direkam" - "Ksalahn: Log rwyat sesi TAK direkam" - "Perekaman log sesi diaktifkan" + "Riwayat sesi dicatat" + "Kesalahan: Riwayat sesi TAK dicatat" + "Log sesi diaktifkan" "Bahasa masukan" "Sentuh lagi untuk menyimpan" "Kamus yang tersedia" diff --git a/java/res/values-ja/strings.xml b/java/res/values-ja/strings.xml index ca13bb9ce..66ba90094 100644 --- a/java/res/values-ja/strings.xml +++ b/java/res/values-ja/strings.xml @@ -107,19 +107,14 @@ "タイムスタンプを記録" "タイムスタンプ記録済み" "セッションを記録しない" - - - - + "セッションログを有効にする" + "セッション履歴全体を記録する" "セッションログ削除中" "セッションログ削除済み" "セッションログ未削除" - - - - - - + "セッション履歴が記録されました" + "エラー: 履歴が記録されていません" + "セッションログが有効になっています" "入力言語" "保存するにはもう一度タップ" "辞書を利用できます" diff --git a/java/res/values-ko/strings.xml b/java/res/values-ko/strings.xml index 3126b2e66..38090d1b9 100644 --- a/java/res/values-ko/strings.xml +++ b/java/res/values-ko/strings.xml @@ -107,19 +107,14 @@ "로그에 타임스탬프를 기록" "타임스탬프를 기록함" "이 세션을 로그하지 마세요." - - - - + "세션 로깅을 사용하도록 설정합니다." + "전체 세션 기록을 로그합니다." "세션 로그 삭제" "세션 로그가 삭제됨" "세션 로그가 삭제되지 않음" - - - - - - + "세션 기록이 로그되었습니다." + "오류: 세션 기록을 로그하지 못했습니다." + "세션 로깅을 사용하고 있습니다." "입력 언어" "저장하려면 다시 터치" "사전 사용 가능" diff --git a/java/res/values-ms/strings-appname.xml b/java/res/values-ms/strings-appname.xml index 6273c6595..73b553751 100644 --- a/java/res/values-ms/strings-appname.xml +++ b/java/res/values-ms/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Papan kekunci Android" "Penyemak ejaan Android" "Tetapan papan kekunci Android" "Tetapan penyemakan ejaan" diff --git a/java/res/values-pl/strings-appname.xml b/java/res/values-pl/strings-appname.xml new file mode 100644 index 000000000..e460644a3 --- /dev/null +++ b/java/res/values-pl/strings-appname.xml @@ -0,0 +1,30 @@ + + + + + "Klawiatura Android" + + + + + + + diff --git a/java/res/values-pl/strings.xml b/java/res/values-pl/strings.xml index 6ffe8dce3..4e25b709c 100644 --- a/java/res/values-pl/strings.xml +++ b/java/res/values-pl/strings.xml @@ -107,19 +107,14 @@ "Znacznik czasu uwagi w dzienniku" "Zapisano znacznik czasu" "Nie rejestruj tej sesji" - - - - + "Włącz rejestrowanie sesji" + "Rejestruj całą historię sesji" "Usuwanie dziennika sesji" "Usunięto dziennik sesji" "Dziennik sesji NIEUSUNIĘTY" - - - - - - + "Historia sesji została zarejestrowana" + "Błąd: historia sesji nie została zarejestrowana." + "Włączono rejestrowanie sesji" "Języki wprowadzania" "Dotknij ponownie, aby zapisać" "Słownik dostępny" diff --git a/java/res/values-pt/strings-appname.xml b/java/res/values-pt/strings-appname.xml index 3987a6dea..d78786d63 100644 --- a/java/res/values-pt/strings-appname.xml +++ b/java/res/values-pt/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Teclado do Android" "Corretor ortográfico do Android" "Configurações de teclado do Android" "Configurações de verificação ortográfica" diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 93666ac3b..8391057e8 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -107,19 +107,14 @@ "Indicar data/hora no reg." "Data/hora registrada" "Não registrar esta sessão" - - - - + "Ativar registro de sessão" + "Registrar histórico de sessão compl." "Excluindo reg. de sessão" "Registro excluído" "Registro NÃO excluído" - - - - - - + "Histórico de sessão registrado" + "Histórico de sessão NÃO registrado" + "Registro de sessão ativado" "Idiomas de entrada" "Toque novamente para salvar" "Dicionário disponível" diff --git a/java/res/values-ro/strings.xml b/java/res/values-ro/strings.xml index 620a5c4a0..b7f491902 100644 --- a/java/res/values-ro/strings.xml +++ b/java/res/values-ro/strings.xml @@ -107,19 +107,14 @@ "Înreg. marc. temp. jurnal" "Marcaj temporal înregis." "Nu înregistraţi sesiunea" - - - - + "Activaţi înregistrarea sesiunii" + "Înregistraţi istoric sesiune întreg" "Se șterge jurnal sesiune" "Jurnal de sesiune șters" "Jurnal sesiune neşters" - - - - - - + "Istoric sesiune înregistrat" + "Eroare: istoric sesiune neînregis." + "Înregistrare sesiune activată" "Limbi de intrare" "Atingeţi din nou pentru a salva" "Dicţionar disponibil" diff --git a/java/res/values-ru/strings.xml b/java/res/values-ru/strings.xml index c50d1dee1..f3ef7aae0 100644 --- a/java/res/values-ru/strings.xml +++ b/java/res/values-ru/strings.xml @@ -107,19 +107,14 @@ "Закладка в журнале" "Закладка сохранена" "Не сохранять этот сеанс" - - - - + "Включить ведение журнала сеансов" + "Записать всю историю сеанса" "Удаление…" "Запись сеанса удалена" "Запись сеанса НЕ удалена" - - - - - - + "История сеанса записана" + "Не удалось записать историю сеанса" + "Ведение журнала включено" "Языки ввода" "Нажмите, чтобы сохранить" "Доступен словарь" diff --git a/java/res/values-sk/strings.xml b/java/res/values-sk/strings.xml index d89d1d3b6..af98da656 100644 --- a/java/res/values-sk/strings.xml +++ b/java/res/values-sk/strings.xml @@ -107,19 +107,14 @@ "Časová pečiatka denníka" "Časová pečiatka zaznamenaná" "Neukl. reláciu do denníka" - - - - + "Povoliť zápis relácií do denníkov" + "Zapísať hist. relácií do denníkov" "Odstraň. denníka relácie" "Denník relácie odstránený" "Denník relácie NIE JE odstr." - - - - - - + "Hist. relácií zapísaná do denníkov" + "Chyba: hist. relácii NEBOLA zapísaná" + "Zápis relácií do denníkov povolený" "Jazyky vstupu" "Opätovným dotykom uložíte" "K dispozícii je slovník" diff --git a/java/res/values-th/strings-appname.xml b/java/res/values-th/strings-appname.xml index 87205d0eb..7fc7e3e43 100644 --- a/java/res/values-th/strings-appname.xml +++ b/java/res/values-th/strings-appname.xml @@ -21,10 +21,7 @@ "แป้นพิมพ์แอนดรอยด์" - - - - - - + "การตรวจสอบการสะกดของแอนดรอยด์" + "การตั้งค่าแป้นพิมพ์แอนดรอยด์" + "การตั้งค่าการตรวจสอบการสะกด" diff --git a/java/res/values-th/strings.xml b/java/res/values-th/strings.xml index c47fc0597..329d3e542 100644 --- a/java/res/values-th/strings.xml +++ b/java/res/values-th/strings.xml @@ -107,19 +107,14 @@ "จดเวลาบันทึกไว้ในบันทึก" "บันทึกเวลาบันทึกแล้ว" "อย่าบันทึกเซสชันนี้" - - - - + "เปิดใช้งานการบันทึกเซสชัน" + "บันทึกประวัติเซสชันทั้งหมด" "กำลังลบบันทึกเซสชัน" "ลบบันทึกเซสชันแล้ว" "บันทึกเซสชันไม่ถูกลบ" - - - - - - + "บันทึกประวัติเซสชันแล้ว" + "ข้อผิดพลาด: ไม่ได้บันทึกประวัติเซสชัน" + "เปิดใช้งานการบันทึกเซสชันแล้ว" "ภาษาสำหรับการป้อนข้อมูล" "แตะอีกครั้งเพื่อบัน​​ทึก" "มีพจนานุกรมให้ใช้งาน" diff --git a/java/res/values-tl/strings.xml b/java/res/values-tl/strings.xml index 766972f46..a54a90887 100644 --- a/java/res/values-tl/strings.xml +++ b/java/res/values-tl/strings.xml @@ -107,19 +107,14 @@ "Tandaan timestamp sa log" "Na-record na timestamp" "Huwag i-log ang session" - - - - + "Paganahin ang pag-log in sa session" + "I-log buong kasaysayan ng session" "Tinatanggl log ng session" "Tinanggal log ng session" "HND ntnggl log ng session" - - - - - - + "Na-log ang kasaysayan ng session" + "Error: DI na-log kasaysayan session" + "Pinapagana ang pag-log ng session" "Mga wika ng input" "Pinduting muli upang i-save" "Available ang diksyunaryo" diff --git a/java/res/values-tr/strings.xml b/java/res/values-tr/strings.xml index 0f5857ab3..2f5737726 100644 --- a/java/res/values-tr/strings.xml +++ b/java/res/values-tr/strings.xml @@ -107,19 +107,14 @@ "Günlüğe zaman damgası koy" "Zaman damgası kaydedildi" "Bu oturumu günlüğe kaydetme" - - - - + "Oturumun günlüğe kaydını etkinleştir" + "Tüm oturum geçmişini günlüğe kaydet" "Oturum günlüğü siliniyor" "Oturum günlüğü silindi" "Oturum günlüğü SİLİNMEDİ" - - - - - - + "Oturum geçmişi günlüğe kaydedildi" + "Hata: Oturum geçmişi KAYDEDİLMEDİ" + "Oturumu günlüğe kaydetme etkinleştirildi" "Giriş dilleri" "Kaydetmek için tekrar dokunun" "Sözlük kullanılabilir" diff --git a/java/res/values-vi/strings.xml b/java/res/values-vi/strings.xml index 789d4da48..94636aaff 100644 --- a/java/res/values-vi/strings.xml +++ b/java/res/values-vi/strings.xml @@ -107,19 +107,14 @@ "Dấu thời gian ghi chú trong nhật ký" "Dấu thời gian đã ghi" "Không ghi nhật ký phiên này" - - - - + "Bật ghi nhật ký phiên" + "Ghi nhật ký toàn bộ lịch sử phiên" "Đang xóa nhật ký phiên" "Đã xóa nhật ký phiên" "Nhật ký phiên KHÔNG bị xóa" - - - - - - + "Lịch sử phiên đã được ghi nhật ký" + "Lỗi: Lịch sử phiên CHƯA được ghi" + "Ghi nhật ký phiên đã được bật" "Ngôn ngữ nhập" "Chạm lại để lưu" "Có sẵn từ điển" diff --git a/java/res/values-zh-rCN/strings-appname.xml b/java/res/values-zh-rCN/strings-appname.xml index 2c1064ad6..f5e12fd5e 100644 --- a/java/res/values-zh-rCN/strings-appname.xml +++ b/java/res/values-zh-rCN/strings-appname.xml @@ -20,8 +20,7 @@ - - + "Android 键盘" "Android 拼写检查工具" "Android 键盘设置" "拼写检查设置" diff --git a/java/res/values-zh-rTW/strings.xml b/java/res/values-zh-rTW/strings.xml index 20c40eb93..a1ee3aebb 100644 --- a/java/res/values-zh-rTW/strings.xml +++ b/java/res/values-zh-rTW/strings.xml @@ -107,19 +107,14 @@ "在紀錄中加註時間戳記" "已記錄時間戳記" "不要記錄這個工作階段" - - - - + "啟用工作階段記錄功能" + "記錄完整工作階段紀錄" "正在刪除工作階段紀錄" "已刪除工作階段紀錄" "「未」刪除工作階段紀錄" - - - - - - + "已記錄工作階段紀錄" + "錯誤:「未」記錄工作階段紀錄" + "已啟用工作階段記錄功能" "輸入語言" "再次輕觸即可儲存" "可使用字典" From 73c5dbd9d262159af3475273b79babe292c75d76 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Fri, 13 Jul 2012 14:25:29 -0700 Subject: [PATCH 3/9] researchLog records versionCode, versionName Bug: 6188932 Change-Id: I3d8502a5397035be5287ea720599e3fda4c669d6 --- .../inputmethod/latin/ResearchLogger.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index 9055d5d32..bd7dade28 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -19,9 +19,12 @@ package com.android.inputmethod.latin; import static com.android.inputmethod.latin.Constants.Subtype.ExtraValue.KEYBOARD_LAYOUT_SET; import android.app.AlertDialog; +import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager.NameNotFoundException; import android.inputmethodservice.InputMethodService; import android.os.Build; import android.text.TextUtils; @@ -101,6 +104,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private Suggest mSuggest; private Dictionary mDictionary; private KeyboardSwitcher mKeyboardSwitcher; + private Context mContext; private ResearchLogger() { } @@ -115,6 +119,7 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang if (ims == null) { Log.w(TAG, "IMS is null; logging is off"); } else { + mContext = ims; mFilesDir = ims.getFilesDir(); if (mFilesDir == null || !mFilesDir.exists()) { Log.w(TAG, "IME storage directory does not exist."); @@ -678,18 +683,31 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang private static final String[] EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL = { "LatinIMEOnStartInputViewInternal", "uuid", "packageName", "inputType", "imeOptions", - "fieldId", "display", "model", "prefs", "outputFormatVersion" + "fieldId", "display", "model", "prefs", "versionCode", "versionName", "outputFormatVersion" }; public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, final SharedPreferences prefs) { + final ResearchLogger researchLogger = getInstance(); + researchLogger.start(); if (editorInfo != null) { - final Object[] values = { - getInstance().mUUIDString, editorInfo.packageName, - Integer.toHexString(editorInfo.inputType), - Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, Build.DISPLAY, - Build.MODEL, prefs, OUTPUT_FORMAT_VERSION - }; - getInstance().enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values); + final Context context = researchLogger.mContext; + try { + final PackageInfo packageInfo; + packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), + 0); + final Integer versionCode = packageInfo.versionCode; + final String versionName = packageInfo.versionName; + final Object[] values = { + researchLogger.mUUIDString, editorInfo.packageName, + Integer.toHexString(editorInfo.inputType), + Integer.toHexString(editorInfo.imeOptions), editorInfo.fieldId, + Build.DISPLAY, Build.MODEL, prefs, versionCode, versionName, + OUTPUT_FORMAT_VERSION + }; + researchLogger.enqueueEvent(EVENTKEYS_LATINIME_ONSTARTINPUTVIEWINTERNAL, values); + } catch (NameNotFoundException e) { + e.printStackTrace(); + } } } From 81dae8d015f63834b2ded44424636b625ece7736 Mon Sep 17 00:00:00 2001 From: Kurt Partridge Date: Fri, 13 Jul 2012 15:35:26 -0700 Subject: [PATCH 4/9] delete old ResearchLog files cleans out the local directory of files that may have persisted accidentally because of system crashes, etc. default lifetime is curently 1 day. Bug: 6188932 Change-Id: I4b51169d6dd0eddb6bf8b661165f88e63782ce7d --- .../inputmethod/latin/ResearchLogger.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/java/src/com/android/inputmethod/latin/ResearchLogger.java b/java/src/com/android/inputmethod/latin/ResearchLogger.java index 9055d5d32..47bd4862f 100644 --- a/java/src/com/android/inputmethod/latin/ResearchLogger.java +++ b/java/src/com/android/inputmethod/latin/ResearchLogger.java @@ -25,6 +25,7 @@ import android.content.SharedPreferences.Editor; import android.inputmethodservice.InputMethodService; import android.os.Build; import android.text.TextUtils; +import android.text.format.DateUtils; import android.util.Log; import android.view.MotionEvent; import android.view.inputmethod.CompletionInfo; @@ -40,6 +41,7 @@ import com.android.inputmethod.latin.RichInputConnection.Range; import com.android.inputmethod.latin.define.ProductionFlag; import java.io.File; +import java.io.FileFilter; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -93,6 +95,9 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang Character.codePointAt("\uE000", 0); // U+E000 is in the "private-use area" // U+E001 is in the "private-use area" /* package for test */ static final String WORD_REPLACEMENT_STRING = "\uE001"; + private static final String PREF_LAST_CLEANUP_TIME = "pref_last_cleanup_time"; + private static final long DURATION_BETWEEN_DIR_CLEANUP_IN_MS = DateUtils.DAY_IN_MILLIS; + private static final long MAX_LOGFILE_AGE_IN_MS = DateUtils.DAY_IN_MILLIS; // set when LatinIME should ignore an onUpdateSelection() callback that // arises from operations in this class private static boolean sLatinIMEExpectingUpdateSelection = false; @@ -124,10 +129,29 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang mUUIDString = getUUID(prefs); sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); prefs.registerOnSharedPreferenceChangeListener(this); + + final long lastCleanupTime = prefs.getLong(PREF_LAST_CLEANUP_TIME, 0L); + final long now = System.currentTimeMillis(); + if (lastCleanupTime + DURATION_BETWEEN_DIR_CLEANUP_IN_MS < now) { + final long timeHorizon = now - MAX_LOGFILE_AGE_IN_MS; + cleanupLoggingDir(mFilesDir, timeHorizon); + Editor e = prefs.edit(); + e.putLong(PREF_LAST_CLEANUP_TIME, now); + e.apply(); + } } mKeyboardSwitcher = keyboardSwitcher; } + private void cleanupLoggingDir(final File dir, final long time) { + for (File file : dir.listFiles()) { + if (file.getName().startsWith(ResearchLogger.FILENAME_PREFIX) && + file.lastModified() < time) { + file.delete(); + } + } + } + private File createLogFile(File filesDir) { final StringBuilder sb = new StringBuilder(); sb.append(FILENAME_PREFIX).append('-'); From c21aca9006216a03d52ebaad22e5e6d1d231237b Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Mon, 16 Jul 2012 13:34:58 -0700 Subject: [PATCH 5/9] Import translations. DO NOT MERGE Change-Id: I2fcbc5265b155035b804cedc019646a239a4d0ad Auto-generated-cl: translation import --- java/res/values-fa/strings.xml | 14 +++++++------- java/res/values-ms/strings.xml | 15 +++++---------- java/res/values-zh-rCN/strings.xml | 15 +++++---------- java/res/values-zu/strings.xml | 4 ++-- 4 files changed, 19 insertions(+), 29 deletions(-) diff --git a/java/res/values-fa/strings.xml b/java/res/values-fa/strings.xml index 1cfac8242..22a0d2ced 100644 --- a/java/res/values-fa/strings.xml +++ b/java/res/values-fa/strings.xml @@ -21,7 +21,7 @@ "صفحه کلید (Android (AOSP" - "گزینه های ورودی" + "گزینه‌های ورودی" "فرمان‌های گزارش‌گیری پژوهش" "غلط‌گیر املای Android (AOSP)" "جستجوی نام مخاطبین" @@ -34,8 +34,8 @@ "سایر گزینه‌ها" "تنظیمات پیشرفته" "گزینه‌هایی برای حرفه‌ای‌ها" - "تغییر به دیگر روشهای ورودی" - "کلید تغییر زبان، سایر ورودیهای زبان را نیز پوشش می‌دهد" + "تغییر به دیگر روش‌های ورودی" + "کلید تغییر زبان، سایر ورودی‌های زبان را نیز پوشش می‌دهد" "کلید تغییر زبان را فشار دهید" "تأخیر در رد کردن کلید نمایشی" "بدون تأخیر" @@ -46,7 +46,7 @@ "فرهنگ‌های لغت افزودنی" "فرهنگ‌ لغت اصلی" "نمایش پیشنهادات تصحیح" - "نمایش واژه های پیشنهادی در حین تایپ" + "نمایش واژه‌های پیشنهادی در حین تایپ" "همیشه نمایش داده شود" "نمایش در حالت عمودی" "همیشه پنهان شود" @@ -106,8 +106,8 @@ "میکروفن در صفحه کلید اصلی" "میکروفن در صفحه کلید نمادها" "ورودی صدا غیرفعال است" - "پیکربندی روش های ورودی" - "زبان های ورودی" + "پیکربندی روش‌های ورودی" + "زبان‌های ورودی" "یادداشت مهر زمان در گزارش" "مهر زمان ثبت شده" "از این جلسه گزارش‌گیری نشود" @@ -123,7 +123,7 @@ "برای ذخیره دوباره لمس کنید" "دیکشنری موجود است" "فعال کردن بازخورد کاربر" - "با ارسال خودکار آمارهای کاربرد و گزارش های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید." + "با ارسال خودکار آمارهای کاربرد و گزارش‌های خرابی به Google، به بهبود این ویرایشگر روش ورودی کمک کنید." "طرح زمینه صفحه کلید" "انگلیسی (بریتانیا)" "انگلیسی (امریکا)" diff --git a/java/res/values-ms/strings.xml b/java/res/values-ms/strings.xml index cdd23a8de..bd961025c 100644 --- a/java/res/values-ms/strings.xml +++ b/java/res/values-ms/strings.xml @@ -107,19 +107,14 @@ "Tanda cap waktu dalam log" "Cap waktu direkodkan" "Jangan log sesi ini" - - - - + "Dayakan log sesi" + "Log sejarah seluruh sesi" "Memadam log sesi" "Log sesi dipadam" "Log sesi TIDAK dipadam" - - - - - - + "Sejarah sesi dilog" + "Ralat: Sejarah sesi TIDAK dilog" + "Log sesi didayakan" "Bahasa input" "Sentuh lagi untuk menyimpan" "Kamus tersedia" diff --git a/java/res/values-zh-rCN/strings.xml b/java/res/values-zh-rCN/strings.xml index ef1c8102e..3d7bffa21 100644 --- a/java/res/values-zh-rCN/strings.xml +++ b/java/res/values-zh-rCN/strings.xml @@ -107,19 +107,14 @@ "标记记录中的时间" "已标记时间" "不记录本次会话" - - - - + "启用会话记录" + "保存整个会话历史记录" "正在删除会话记录" "会话记录已删除" "未能删除会话记录" - - - - - - + "会话历史记录已保存" + "错误:会话历史记录未保存" + "会话记录已启用" "输入语言" "再次触摸即可保存" "有可用词典" diff --git a/java/res/values-zu/strings.xml b/java/res/values-zu/strings.xml index da222092e..575c30d4a 100644 --- a/java/res/values-zu/strings.xml +++ b/java/res/values-zu/strings.xml @@ -112,8 +112,8 @@ "Isusa ifayela lokungena lesikhathi" "Ifayela lokungena lesikhathi lisusiwe" "Ifayela lokungena lesikhathi alisusiwe" - "Umlando wesikhathi ukhiyiwe" - "Iphutha: Umlando wesikhathi awukhiyiwe" + "Umlando wesikhathi ukufayela lokungena" + "Iphutha: Umlando wesikhathi awufakwanga kufayela lokungena" "Ukungena kwesikhathi kunikwe amandla" "Izilimi zokufakwayo" "Thinta futhi ukuze ulondoloze" From af2c11525324d1cb48fce249c907f5906f0524dc Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Tue, 17 Jul 2012 11:32:12 +0900 Subject: [PATCH 6/9] Opening punctuations have a priority in Spanish keyboard Bug: 6737535 Change-Id: I87442eb978ac68be3d3df99eed8a92877a6f4ab0 --- java/res/xml-sw600dp/rowkeys_symbols3.xml | 2 +- java/res/xml/rowkeys_symbols3.xml | 2 +- .../keyboard/internal/KeyboardTextsSet.java | 201 ++++++++---------- .../values-es/donottranslate-more-keys.xml | 12 +- .../res/values/donottranslate-more-keys.xml | 1 - 5 files changed, 99 insertions(+), 119 deletions(-) diff --git a/java/res/xml-sw600dp/rowkeys_symbols3.xml b/java/res/xml-sw600dp/rowkeys_symbols3.xml index 4bfa0d730..30fba3812 100644 --- a/java/res/xml-sw600dp/rowkeys_symbols3.xml +++ b/java/res/xml-sw600dp/rowkeys_symbols3.xml @@ -49,7 +49,7 @@ ç,ć,č - "!fixedColumnOrder!9,\",\',#,-,¡,!,¿,\\,,\?,\@,&,\\%,+,;,:,/,(,)" - ¡ - "¡,!" - ¿ - "¿,\?" + "!fixedColumnOrder!9,¡,\",\',#,-,:,!,\\,,\?,¿,\@,&,\\%,+,;,/,(,)" - "¡" + "!,¡" - "¿" - "!" - "\?" + "\?,¿" diff --git a/tools/maketext/res/values/donottranslate-more-keys.xml b/tools/maketext/res/values/donottranslate-more-keys.xml index 922b42d1b..7f1940a57 100644 --- a/tools/maketext/res/values/donottranslate-more-keys.xml +++ b/tools/maketext/res/values/donottranslate-more-keys.xml @@ -158,7 +158,6 @@ ⁿ,∅ , - ! \? ; % From 8788dffe6f77af7cfa0a33ec012b68c76fdab040 Mon Sep 17 00:00:00 2001 From: Ken Wakasa Date: Tue, 17 Jul 2012 18:36:37 +0900 Subject: [PATCH 7/9] Increase the config_key_hysteresis_distance value for tablet form factor devices bug: 6745169 Change-Id: I4f0c018748b12d42d5ef587d93df3c5521623b36 --- java/res/values-sw600dp/config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/java/res/values-sw600dp/config.xml b/java/res/values-sw600dp/config.xml index 2f35d9ae5..745d3b995 100644 --- a/java/res/values-sw600dp/config.xml +++ b/java/res/values-sw600dp/config.xml @@ -34,6 +34,7 @@ + 40.0dp false From e3c0301b31fd62bcb07db7bdb57dc542b4b4a358 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Tue, 17 Jul 2012 13:29:26 -0700 Subject: [PATCH 8/9] Import translations. DO NOT MERGE Change-Id: If1f6cea5414e0033139babda4a8afc459fd656cc Auto-generated-cl: translation import --- java/res/values-et/strings.xml | 6 +++--- java/res/values-it/strings.xml | 2 +- java/res/values-pt-rPT/strings.xml | 8 ++++---- java/res/values-pt/strings.xml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/java/res/values-et/strings.xml b/java/res/values-et/strings.xml index ae98198ce..6dd86aaf2 100644 --- a/java/res/values-et/strings.xml +++ b/java/res/values-et/strings.xml @@ -107,13 +107,13 @@ "Märgi ajatempel logisse" "Salvestatud ajatemplid" "Ära logi seda seanssi" - "Lubage seansi logimine" - "Logige kogu seansi ajalugu" + "Luba seansi logimine" + "Logi kogu seansi ajalugu" "Seansi logi kustutamine" "Seansi logi kustutatud" "Seansi logi EI kustutatud" "Seansi ajalugu on logitud" - "Viga: seansi ajalugu EI OLE logitud" + "Viga: seansi ajalugu EI logitud" "Seansi logimine on lubatud" "Sisestuskeeled" "Salvestamiseks puudutage uuesti" diff --git a/java/res/values-it/strings.xml b/java/res/values-it/strings.xml index b23c516e9..6522bb91c 100644 --- a/java/res/values-it/strings.xml +++ b/java/res/values-it/strings.xml @@ -113,7 +113,7 @@ "Log di sessione eliminato" "Log sessione non eliminato" "Cronologia sessione registrata" - "Errore: cron. sessione NON registr." + "Errore: cronologia NON registrata" "Registrazione sessioni attivata" "Lingue comandi" "Tocca di nuovo per salvare" diff --git a/java/res/values-pt-rPT/strings.xml b/java/res/values-pt-rPT/strings.xml index f16070bb4..4ffc7cac0 100644 --- a/java/res/values-pt-rPT/strings.xml +++ b/java/res/values-pt-rPT/strings.xml @@ -108,13 +108,13 @@ "Carimbo de data gravado" "Não registar esta sessão" "Ativar registos de sessão" - "Registar hist. de sessões completo" + "Registar hist. de sessão completo" "A eliminar reg. da sessão" "Reg. de sessão eliminado" "Reg. de sessão NÃO elim." - "Histórico de sessões registado" - "Erro: hist. de sessões NÃO regist." - "Registo de sessões ativado" + "Histórico de sessão registado" + "Erro: hist. de sessão NÃO regist." + "Registo de sessão ativado" "Idiomas de introdução" "Toque novamente para guardar" "Dicionário disponível" diff --git a/java/res/values-pt/strings.xml b/java/res/values-pt/strings.xml index 8391057e8..d1ce05aa3 100644 --- a/java/res/values-pt/strings.xml +++ b/java/res/values-pt/strings.xml @@ -108,7 +108,7 @@ "Data/hora registrada" "Não registrar esta sessão" "Ativar registro de sessão" - "Registrar histórico de sessão compl." + "Regist. histórico de sessão inteiro" "Excluindo reg. de sessão" "Registro excluído" "Registro NÃO excluído" From 3ec31f4971c3db7ef73488859609870d15f5dc69 Mon Sep 17 00:00:00 2001 From: "Tadashi G. Takaoka" Date: Wed, 18 Jul 2012 14:05:01 +0900 Subject: [PATCH 9/9] A gesture should not start from the delete key Change-Id: I5c8c7665454b7f10f944f307431dfffe20cf3134 --- java/src/com/android/inputmethod/keyboard/Keyboard.java | 3 +-- .../android/inputmethod/keyboard/internal/GestureTracker.java | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java index 1aec00129..f1a35b212 100644 --- a/java/src/com/android/inputmethod/keyboard/Keyboard.java +++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java @@ -87,7 +87,6 @@ public class Keyboard { public static final int CODE_CLOSING_SQUARE_BRACKET = ']'; public static final int CODE_CLOSING_CURLY_BRACKET = '}'; public static final int CODE_CLOSING_ANGLE_BRACKET = '>'; - private static final int MINIMUM_LETTER_CODE = CODE_TAB; /** Special keys code. Must be negative. * These should be aligned with KeyboardCodesSet.ID_TO_NAME[], @@ -217,7 +216,7 @@ public class Keyboard { } public static boolean isLetterCode(int code) { - return code >= MINIMUM_LETTER_CODE; + return code >= CODE_SPACE; } public static class Params { diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java index f98911445..dfd697a7a 100644 --- a/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java +++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTracker.java @@ -104,7 +104,8 @@ public class GestureTracker { public void onDownEvent(PointerTracker tracker, int x, int y, long eventTime, Key key) { mIsPossibleGesture = false; - if (GESTURE_ON && mIsAlphabetKeyboard && key != null && !key.isModifier()) { + // A gesture should start only from the letter key. + if (GESTURE_ON && mIsAlphabetKeyboard && key != null && Keyboard.isLetterCode(key.mCode)) { mIsPossibleGesture = true; addPointToStroke(x, y, 0, tracker.mPointerId, false); }