aboutsummaryrefslogtreecommitdiffstats
path: root/java/src
diff options
context:
space:
mode:
Diffstat (limited to 'java/src')
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java11
-rw-r--r--java/src/com/android/inputmethod/keyboard/KeyboardView.java10
-rw-r--r--java/src/com/android/inputmethod/keyboard/MainKeyboardView.java159
-rw-r--r--java/src/com/android/inputmethod/keyboard/PointerTracker.java98
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java1
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java113
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java3
-rw-r--r--java/src/com/android/inputmethod/latin/LatinIME.java11
-rw-r--r--java/src/com/android/inputmethod/latin/Suggest.java7
-rw-r--r--java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java39
-rw-r--r--java/src/com/android/inputmethod/research/ResearchLogger.java34
11 files changed, 308 insertions, 178 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index bb1aa4776..8880af48c 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -273,7 +273,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public void startDoubleTapShiftKeyTimer() {
final MainKeyboardView keyboardView = getMainKeyboardView();
if (keyboardView != null) {
- keyboardView.getTimerProxy().startDoubleTapShiftKeyTimer();
+ keyboardView.startDoubleTapShiftKeyTimer();
}
}
@@ -282,7 +282,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public void cancelDoubleTapShiftKeyTimer() {
final MainKeyboardView keyboardView = getMainKeyboardView();
if (keyboardView != null) {
- keyboardView.getTimerProxy().cancelDoubleTapShiftKeyTimer();
+ keyboardView.cancelDoubleTapShiftKeyTimer();
}
}
@@ -290,7 +290,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
@Override
public boolean isInDoubleTapShiftKeyTimeout() {
final MainKeyboardView keyboardView = getMainKeyboardView();
- return keyboardView != null && keyboardView.getTimerProxy().isInDoubleTapShiftKeyTimeout();
+ return keyboardView != null && keyboardView.isInDoubleTapShiftKeyTimeout();
}
/**
@@ -314,10 +314,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
R.layout.input_view, null);
mKeyboardView = (MainKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
- if (isHardwareAcceleratedDrawingEnabled) {
- mKeyboardView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
- // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
- }
+ mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
mKeyboardView.setKeyboardActionListener(mLatinIME);
// This always needs to be set since the accessibility state can
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index 254b20b87..054c503d8 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -154,6 +154,12 @@ public class KeyboardView extends View {
Color.red(color), Color.green(color), Color.blue(color));
}
+ public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
+ if (!enabled) return;
+ // TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+ }
+
/**
* Attaches a keyboard to this view. The keyboard can be switched at any time and the
* view will re-layout itself to accommodate the keyboard.
@@ -605,4 +611,8 @@ public class KeyboardView extends View {
super.onDetachedFromWindow();
freeOffscreenBuffer();
}
+
+ public void deallocateMemory() {
+ freeOffscreenBuffer();
+ }
}
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 43baf6172..6782317d0 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -53,6 +53,7 @@ import com.android.inputmethod.keyboard.internal.GestureFloatingPreviewText;
import com.android.inputmethod.keyboard.internal.GestureTrailsPreview;
import com.android.inputmethod.keyboard.internal.KeyDrawParams;
import com.android.inputmethod.keyboard.internal.KeyPreviewDrawParams;
+import com.android.inputmethod.keyboard.internal.NonDistinctMultitouchHelper;
import com.android.inputmethod.keyboard.internal.PreviewPlacerView;
import com.android.inputmethod.keyboard.internal.SlidingKeyInputPreview;
import com.android.inputmethod.latin.Constants;
@@ -179,9 +180,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private int mGestureFloatingPreviewTextLingerTimeout;
private KeyDetector mKeyDetector;
- private final boolean mHasDistinctMultitouch;
- private int mOldPointerCount = 1;
- private Key mOldKey;
+ private final NonDistinctMultitouchHelper mNonDistinctMultitouchHelper;
private final KeyTimerHandler mKeyTimerHandler;
@@ -193,8 +192,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 3;
private static final int MSG_UPDATE_BATCH_INPUT = 4;
- private final int mKeyRepeatStartTimeout;
- private final int mKeyRepeatInterval;
private final int mIgnoreAltCodeKeyTimeout;
private final int mGestureRecognitionUpdateTime;
@@ -202,10 +199,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
final TypedArray mainKeyboardViewAttr) {
super(outerInstance);
- mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
- mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
- R.styleable.MainKeyboardView_keyRepeatInterval, 0);
mIgnoreAltCodeKeyTimeout = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_ignoreAltCodeKeyTimeout, 0);
mGestureRecognitionUpdateTime = mainKeyboardViewAttr.getInt(
@@ -224,17 +217,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
startWhileTypingFadeinAnimation(keyboardView);
break;
case MSG_REPEAT_KEY:
- final Key currentKey = tracker.getKey();
- final int code = msg.arg1;
- if (currentKey != null && currentKey.mCode == code) {
- startKeyRepeatTimer(tracker, mKeyRepeatInterval);
- startTypingStateTimer(currentKey);
- final KeyboardActionListener listener =
- keyboardView.getKeyboardActionListener();
- listener.onPressKey(code, true /* isRepeatKey */, true /* isSinglePointer */);
- listener.onCodeInput(code,
- Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE);
- }
+ tracker.onKeyRepeat(msg.arg1);
break;
case MSG_LONGPRESS_KEY:
keyboardView.onLongPress(tracker);
@@ -246,19 +229,15 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
}
- private void startKeyRepeatTimer(final PointerTracker tracker, final long delay) {
+ @Override
+ public void startKeyRepeatTimer(final PointerTracker tracker, final int delay) {
final Key key = tracker.getKey();
- if (key == null) {
+ if (key == null || delay == 0) {
return;
}
sendMessageDelayed(obtainMessage(MSG_REPEAT_KEY, key.mCode, 0, tracker), delay);
}
- @Override
- public void startKeyRepeatTimer(final PointerTracker tracker) {
- startKeyRepeatTimer(tracker, mKeyRepeatStartTimeout);
- }
-
public void cancelKeyRepeatTimer() {
removeMessages(MSG_REPEAT_KEY);
}
@@ -443,13 +422,16 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
public MainKeyboardView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
+ PointerTracker.init(getResources());
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
final boolean forceNonDistinctMultitouch = prefs.getBoolean(
DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, false);
final boolean hasDistinctMultitouch = context.getPackageManager()
- .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT);
- mHasDistinctMultitouch = hasDistinctMultitouch && !forceNonDistinctMultitouch;
- PointerTracker.init(getResources());
+ .hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH_DISTINCT)
+ && !forceNonDistinctMultitouch;
+ mNonDistinctMultitouchHelper = hasDistinctMultitouch ? null
+ : new NonDistinctMultitouchHelper();
+
mPreviewPlacerView = new PreviewPlacerView(context, attrs);
final TypedArray mainKeyboardViewAttr = context.obtainStyledAttributes(
@@ -530,6 +512,12 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
mKeyboardActionListener = KeyboardActionListener.EMPTY_LISTENER;
}
+ @Override
+ public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
+ super.setHardwareAcceleratedDrawingEnabled(enabled);
+ mPreviewPlacerView.setHardwareAcceleratedDrawingEnabled(enabled);
+ }
+
private ObjectAnimator loadObjectAnimator(final int resId, final Object target) {
if (resId == 0) {
// TODO: Stop returning null.
@@ -1027,6 +1015,18 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
}
+ public void startDoubleTapShiftKeyTimer() {
+ mKeyTimerHandler.startDoubleTapShiftKeyTimer();
+ }
+
+ public void cancelDoubleTapShiftKeyTimer() {
+ mKeyTimerHandler.cancelDoubleTapShiftKeyTimer();
+ }
+
+ public boolean isInDoubleTapShiftKeyTimeout() {
+ return mKeyTimerHandler.isInDoubleTapShiftKeyTimeout();
+ }
+
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (AccessibilityUtils.getInstance().isTouchExplorationEnabled()) {
@@ -1040,100 +1040,31 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
if (getKeyboard() == null) {
return false;
}
- // TODO: Add multi-touch to single-touch event converter for non-distinct multi-touch
- // device.
+ if (mNonDistinctMultitouchHelper != null) {
+ if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) {
+ // Key repeating timer will be canceled if 2 or more keys are in action.
+ mKeyTimerHandler.cancelKeyRepeatTimer();
+ }
+ // Non distinct multitouch screen support
+ mNonDistinctMultitouchHelper.processMotionEvent(me, this);
+ return true;
+ }
return processMotionEvent(me);
}
public boolean processMotionEvent(final MotionEvent me) {
- final boolean nonDistinctMultitouch = !mHasDistinctMultitouch;
- final int action = me.getActionMasked();
- final int pointerCount = me.getPointerCount();
- final int oldPointerCount = mOldPointerCount;
- mOldPointerCount = pointerCount;
-
- // TODO: cleanup this code into a multi-touch to single-touch event converter class?
- // If the device does not have distinct multi-touch support panel, ignore all multi-touch
- // events except a transition from/to single-touch.
- if (nonDistinctMultitouch && pointerCount > 1 && oldPointerCount > 1) {
- return true;
- }
-
- final long eventTime = me.getEventTime();
- final int index = me.getActionIndex();
- final int id = me.getPointerId(index);
- final int x = (int)me.getX(index);
- final int y = (int)me.getY(index);
-
- // TODO: This might be moved to the tracker.processMotionEvent() call below.
if (LatinImeLogger.sUsabilityStudy) {
UsabilityStudyLogUtils.writeMotionEvent(me);
}
- // TODO: This should be moved to the tracker.processMotionEvent() call below.
// Currently the same "move" event is being logged twice.
if (ProductionFlag.USES_DEVELOPMENT_ONLY_DIAGNOSTICS) {
- ResearchLogger.mainKeyboardView_processMotionEvent(
- me, action, eventTime, index, id, x, y);
- }
-
- if (mKeyTimerHandler.isInKeyRepeat()) {
- final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
- // Key repeating timer will be canceled if 2 or more keys are in action, and current
- // event (UP or DOWN) is non-modifier key.
- if (pointerCount > 1 && !tracker.isModifier()) {
- mKeyTimerHandler.cancelKeyRepeatTimer();
- }
- // Up event will pass through.
- }
-
- // TODO: cleanup this code into a multi-touch to single-touch event converter class?
- // Translate mutli-touch event to single-touch events on the device that has no distinct
- // multi-touch panel.
- if (nonDistinctMultitouch) {
- // Use only main (id=0) pointer tracker.
- final PointerTracker tracker = PointerTracker.getPointerTracker(0, this);
- if (pointerCount == 1 && oldPointerCount == 2) {
- // Multi-touch to single touch transition.
- // Send a down event for the latest pointer if the key is different from the
- // previous key.
- final Key newKey = tracker.getKeyOn(x, y);
- if (mOldKey != newKey) {
- tracker.onDownEvent(x, y, eventTime, this);
- if (action == MotionEvent.ACTION_UP) {
- tracker.onUpEvent(x, y, eventTime);
- }
- }
- } else if (pointerCount == 2 && oldPointerCount == 1) {
- // Single-touch to multi-touch transition.
- // Send an up event for the last pointer.
- final int[] lastCoords = CoordinateUtils.newInstance();
- mOldKey = tracker.getKeyOn(
- CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords));
- tracker.onUpEvent(
- CoordinateUtils.x(lastCoords), CoordinateUtils.y(lastCoords), eventTime);
- } else if (pointerCount == 1 && oldPointerCount == 1) {
- tracker.processMotionEvent(action, x, y, eventTime, this);
- } else {
- Log.w(TAG, "Unknown touch panel behavior: pointer count is " + pointerCount
- + " (old " + oldPointerCount + ")");
- }
- return true;
- }
-
- if (action == MotionEvent.ACTION_MOVE) {
- for (int i = 0; i < pointerCount; i++) {
- final int pointerId = me.getPointerId(i);
- final PointerTracker tracker = PointerTracker.getPointerTracker(
- pointerId, this);
- final int px = (int)me.getX(i);
- final int py = (int)me.getY(i);
- tracker.onMoveEvent(px, py, eventTime, me);
- }
- } else {
- final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
- tracker.processMotionEvent(action, x, y, eventTime, this);
+ ResearchLogger.mainKeyboardView_processMotionEvent(me);
}
+ final int index = me.getActionIndex();
+ final int id = me.getPointerId(index);
+ final PointerTracker tracker = PointerTracker.getPointerTracker(id, this);
+ tracker.processMotionEvent(me, this);
return true;
}
@@ -1330,7 +1261,9 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
}
}
+ @Override
public void deallocateMemory() {
+ super.deallocateMemory();
mGestureTrailsPreview.deallocateMemory();
}
}
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index 20fc109da..ab5fee99d 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -94,7 +94,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public interface TimerProxy {
public void startTypingStateTimer(Key typedKey);
public boolean isTypingState();
- public void startKeyRepeatTimer(PointerTracker tracker);
+ public void startKeyRepeatTimer(PointerTracker tracker, int delay);
public void startLongPressTimer(PointerTracker tracker, int delay);
public void cancelLongPressTimer();
public void startDoubleTapShiftKeyTimer();
@@ -111,7 +111,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
@Override
public boolean isTypingState() { return false; }
@Override
- public void startKeyRepeatTimer(PointerTracker tracker) {}
+ public void startKeyRepeatTimer(PointerTracker tracker, int delay) {}
@Override
public void startLongPressTimer(PointerTracker tracker, int delay) {}
@Override
@@ -138,6 +138,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
public final int mTouchNoiseThresholdTime;
public final int mTouchNoiseThresholdDistance;
public final int mSuppressKeyPreviewAfterBatchInputDuration;
+ public final int mKeyRepeatStartTimeout;
+ public final int mKeyRepeatInterval;
public final int mLongPressShiftLockTimeout;
public static final PointerTrackerParams DEFAULT = new PointerTrackerParams();
@@ -147,6 +149,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mTouchNoiseThresholdTime = 0;
mTouchNoiseThresholdDistance = 0;
mSuppressKeyPreviewAfterBatchInputDuration = 0;
+ mKeyRepeatStartTimeout = 0;
+ mKeyRepeatInterval = 0;
mLongPressShiftLockTimeout = 0;
}
@@ -159,6 +163,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
R.styleable.MainKeyboardView_touchNoiseThresholdDistance, 0);
mSuppressKeyPreviewAfterBatchInputDuration = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_suppressKeyPreviewAfterBatchInputDuration, 0);
+ mKeyRepeatStartTimeout = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatStartTimeout, 0);
+ mKeyRepeatInterval = mainKeyboardViewAttr.getInt(
+ R.styleable.MainKeyboardView_keyRepeatInterval, 0);
mLongPressShiftLockTimeout = mainKeyboardViewAttr.getInt(
R.styleable.MainKeyboardView_longPressShiftLockTimeout, 0);
}
@@ -470,6 +478,10 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mPointerId = id;
mGestureStrokeWithPreviewPoints = new GestureStrokeWithPreviewPoints(
id, sGestureStrokeParams, sGesturePreviewParams);
+ setKeyEventHandler(handler);
+ }
+
+ private void setKeyEventHandler(final KeyEventHandler handler) {
setKeyDetectorInner(handler.getKeyDetector());
mListener = handler.getKeyboardActionListener();
mDrawingProxy = handler.getDrawingProxy();
@@ -477,7 +489,8 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
// Returns true if keyboard has been changed by this callback.
- private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key) {
+ private boolean callListenerOnPressAndCheckKeyboardLayoutChange(final Key key,
+ final boolean isRepeatKey) {
// While gesture input is going on, this method should be a no-operation. But when gesture
// input has been canceled, <code>sInGesture</code> and <code>mIsDetectingGesture</code>
// are set to false. To keep this method is a no-operation,
@@ -487,17 +500,17 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
final boolean ignoreModifierKey = mIsInSlidingKeyInput && key.isModifier();
if (DEBUG_LISTENER) {
- Log.d(TAG, String.format("[%d] onPress : %s%s%s", mPointerId,
+ Log.d(TAG, String.format("[%d] onPress : %s%s%s%s", mPointerId,
KeyDetector.printableCode(key),
ignoreModifierKey ? " ignoreModifier" : "",
- key.isEnabled() ? "" : " disabled"));
+ key.isEnabled() ? "" : " disabled",
+ isRepeatKey ? " repeat" : ""));
}
if (ignoreModifierKey) {
return false;
}
if (key.isEnabled()) {
- mListener.onPressKey(key.mCode, false /* isRepeatKey */,
- getActivePointerTrackerCount() == 1);
+ mListener.onPressKey(key.mCode, isRepeatKey, getActivePointerTrackerCount() == 1);
final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged;
mKeyboardLayoutHasBeenChanged = false;
mTimerProxy.startTypingStateTimer(key);
@@ -857,8 +870,23 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
mListener.onCancelBatchInput();
}
- public void processMotionEvent(final int action, final int x, final int y, final long eventTime,
- final KeyEventHandler handler) {
+ public void processMotionEvent(final MotionEvent me, final KeyEventHandler handler) {
+ final int action = me.getActionMasked();
+ final long eventTime = me.getEventTime();
+ if (action == MotionEvent.ACTION_MOVE) {
+ final int pointerCount = me.getPointerCount();
+ for (int index = 0; index < pointerCount; index++) {
+ final int id = me.getPointerId(index);
+ final PointerTracker tracker = getPointerTracker(id, handler);
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ tracker.onMoveEvent(x, y, eventTime, me);
+ }
+ return;
+ }
+ final int index = me.getActionIndex();
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
@@ -868,24 +896,18 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
case MotionEvent.ACTION_POINTER_UP:
onUpEvent(x, y, eventTime);
break;
- case MotionEvent.ACTION_MOVE:
- onMoveEvent(x, y, eventTime, null);
- break;
case MotionEvent.ACTION_CANCEL:
onCancelEvent(x, y, eventTime);
break;
}
}
- public void onDownEvent(final int x, final int y, final long eventTime,
+ private void onDownEvent(final int x, final int y, final long eventTime,
final KeyEventHandler handler) {
if (DEBUG_EVENT) {
printTouchEvent("onDownEvent:", x, y, eventTime);
}
- mDrawingProxy = handler.getDrawingProxy();
- mTimerProxy = handler.getTimerProxy();
- setKeyboardActionListener(handler.getKeyboardActionListener());
- setKeyDetectorInner(handler.getKeyDetector());
+ setKeyEventHandler(handler);
// Naive up-to-down noise filter.
final long deltaT = eventTime - mUpTime;
if (deltaT < sParams.mTouchNoiseThresholdTime) {
@@ -917,7 +939,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
// A gesture should start only from a non-modifier key.
mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
- && key != null && !key.isModifier();
+ && key != null && !key.isModifier() && !key.isRepeatable();
if (mIsDetectingGesture) {
if (getActivePointerTrackerCount() == 1) {
sGestureFirstDownTime = eventTime;
@@ -945,7 +967,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update key according to the new
// keyboard layout.
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false /* isRepeatKey */)) {
key = onDownKey(x, y, eventTime);
}
@@ -995,7 +1017,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- public void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) {
+ private void onMoveEvent(final int x, final int y, final long eventTime, final MotionEvent me) {
if (DEBUG_MOVE_EVENT) {
printTouchEvent("onMoveEvent:", x, y, eventTime);
}
@@ -1035,7 +1057,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
// at {@link #setKeyboard}. In those cases, we should update key according
// to the new keyboard layout.
Key key = newKey;
- if (callListenerOnPressAndCheckKeyboardLayoutChange(key)) {
+ if (callListenerOnPressAndCheckKeyboardLayoutChange(key, false /* isRepeatKey */)) {
key = onMoveKey(x, y);
}
onMoveToNewKey(key, x, y);
@@ -1183,7 +1205,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- public void onUpEvent(final int x, final int y, final long eventTime) {
+ private void onUpEvent(final int x, final int y, final long eventTime) {
if (DEBUG_EVENT) {
printTouchEvent("onUpEvent :", x, y, eventTime);
}
@@ -1283,7 +1305,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
sPointerTrackerQueue.remove(this);
}
- public void onCancelEvent(final int x, final int y, final long eventTime) {
+ private void onCancelEvent(final int x, final int y, final long eventTime) {
if (DEBUG_EVENT) {
printTouchEvent("onCancelEvt:", x, y, eventTime);
}
@@ -1304,16 +1326,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
}
}
- private void startRepeatKey(final Key key) {
- if (sInGesture) return;
- if (key == null) return;
- if (!key.isRepeatable()) return;
- // Don't start key repeat when we are in sliding input mode.
- if (mIsInSlidingKeyInput) return;
- detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
- mTimerProxy.startKeyRepeatTimer(this);
- }
-
private boolean isMajorEnoughMoveToBeOnNewKey(final int x, final int y, final long eventTime,
final Key newKey) {
if (mKeyDetector == null) {
@@ -1394,6 +1406,26 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
callListenerOnRelease(key, code, false /* withSliding */);
}
+ private void startRepeatKey(final Key key) {
+ if (sInGesture) return;
+ if (key == null) return;
+ if (!key.isRepeatable()) return;
+ // Don't start key repeat when we are in sliding input mode.
+ if (mIsInSlidingKeyInput) return;
+ detectAndSendKey(key, key.mX, key.mY, SystemClock.uptimeMillis());
+ mTimerProxy.startKeyRepeatTimer(this, sParams.mKeyRepeatStartTimeout);
+ }
+
+ public void onKeyRepeat(final int code) {
+ final Key key = getKey();
+ if (key == null || key.mCode != code) {
+ return;
+ }
+ mTimerProxy.startKeyRepeatTimer(this, sParams.mKeyRepeatInterval);
+ callListenerOnPressAndCheckKeyboardLayoutChange(key, true /* isRepeatKey */);
+ callListenerOnCodeInput(key, code, mKeyX, mKeyY, SystemClock.uptimeMillis());
+ }
+
private void printTouchEvent(final String title, final int x, final int y,
final long eventTime) {
final Key key = mKeyDetector.detectHitKey(x, y);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
index d4c25941c..19e995548 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/GestureTrailsPreview.java
@@ -110,6 +110,7 @@ public final class GestureTrailsPreview extends AbstractDrawingPreview {
private void freeOffscreenBuffer() {
mOffscreenCanvas.setBitmap(null);
+ mOffscreenCanvas.setMatrix(null);
if (mOffscreenBuffer != null) {
mOffscreenBuffer.recycle();
mOffscreenBuffer = null;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java
new file mode 100644
index 000000000..a0935b985
--- /dev/null
+++ b/java/src/com/android/inputmethod/keyboard/internal/NonDistinctMultitouchHelper.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.inputmethod.keyboard.internal;
+
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.inputmethod.keyboard.Key;
+import com.android.inputmethod.keyboard.PointerTracker;
+import com.android.inputmethod.keyboard.PointerTracker.KeyEventHandler;
+import com.android.inputmethod.latin.utils.CoordinateUtils;
+
+public final class NonDistinctMultitouchHelper {
+ private static final String TAG = NonDistinctMultitouchHelper.class.getSimpleName();
+
+ private int mOldPointerCount = 1;
+ private Key mOldKey;
+ private int[] mLastCoords = CoordinateUtils.newInstance();
+
+ public void processMotionEvent(final MotionEvent me, final KeyEventHandler keyEventHandler) {
+ final int pointerCount = me.getPointerCount();
+ final int oldPointerCount = mOldPointerCount;
+ mOldPointerCount = pointerCount;
+ // Ignore continuous multi-touch events because we can't trust the coordinates
+ // in multi-touch events.
+ if (pointerCount > 1 && oldPointerCount > 1) {
+ return;
+ }
+
+ // Use only main (id=0) pointer tracker.
+ final PointerTracker mainTracker = PointerTracker.getPointerTracker(0, keyEventHandler);
+ final int action = me.getActionMasked();
+ final int index = me.getActionIndex();
+ final long eventTime = me.getEventTime();
+ final long downTime = me.getDownTime();
+
+ // In single-touch.
+ if (oldPointerCount == 1 && pointerCount == 1) {
+ if (me.getPointerId(index) == mainTracker.mPointerId) {
+ mainTracker.processMotionEvent(me, keyEventHandler);
+ return;
+ }
+ // Inject a copied event.
+ injectMotionEvent(action, me.getX(index), me.getY(index), downTime, eventTime,
+ mainTracker, keyEventHandler);
+ return;
+ }
+
+ // Single-touch to multi-touch transition.
+ if (oldPointerCount == 1 && pointerCount == 2) {
+ // Send an up event for the last pointer, be cause we can't trust the coordinates of
+ // this multi-touch event.
+ mainTracker.getLastCoordinates(mLastCoords);
+ final int x = CoordinateUtils.x(mLastCoords);
+ final int y = CoordinateUtils.y(mLastCoords);
+ mOldKey = mainTracker.getKeyOn(x, y);
+ // Inject an artifact up event for the old key.
+ injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime,
+ mainTracker, keyEventHandler);
+ return;
+ }
+
+ // Multi-touch to single-touch transition.
+ if (oldPointerCount == 2 && pointerCount == 1) {
+ // Send a down event for the latest pointer if the key is different from the previous
+ // key.
+ final int x = (int)me.getX(index);
+ final int y = (int)me.getY(index);
+ final Key newKey = mainTracker.getKeyOn(x, y);
+ if (mOldKey != newKey) {
+ // Inject an artifact down event for the new key.
+ // An artifact up event for the new key will usually be injected as a single-touch.
+ injectMotionEvent(MotionEvent.ACTION_DOWN, x, y, downTime, eventTime,
+ mainTracker, keyEventHandler);
+ if (action == MotionEvent.ACTION_UP) {
+ // Inject an artifact up event for the new key also.
+ injectMotionEvent(MotionEvent.ACTION_UP, x, y, downTime, eventTime,
+ mainTracker, keyEventHandler);
+ }
+ }
+ return;
+ }
+
+ Log.w(TAG, "Unknown touch panel behavior: pointer count is "
+ + pointerCount + " (previously " + oldPointerCount + ")");
+ }
+
+ private static void injectMotionEvent(final int action, final float x, final float y,
+ final long downTime, final long eventTime, final PointerTracker tracker,
+ final KeyEventHandler handler) {
+ final MotionEvent me = MotionEvent.obtain(
+ downTime, eventTime, action, x, y, 0 /* metaState */);
+ try {
+ tracker.processMotionEvent(me, handler);
+ } finally {
+ me.recycle();
+ }
+ }
+}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
index 3388c5701..4c8607da8 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/PreviewPlacerView.java
@@ -37,7 +37,10 @@ public final class PreviewPlacerView extends RelativeLayout {
public PreviewPlacerView(final Context context, final AttributeSet attrs) {
super(context, attrs);
setWillNotDraw(false);
+ }
+ public void setHardwareAcceleratedDrawingEnabled(final boolean enabled) {
+ if (!enabled) return;
final Paint layerPaint = new Paint();
layerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER));
setLayerType(LAYER_TYPE_HARDWARE, layerPaint);
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 614c14308..719c7c81f 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -76,6 +76,7 @@ import com.android.inputmethod.keyboard.MainKeyboardView;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
import com.android.inputmethod.latin.define.ProductionFlag;
import com.android.inputmethod.latin.personalization.PersonalizationDictionaryHelper;
+import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.settings.SettingsActivity;
@@ -170,6 +171,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private boolean mIsMainDictionaryAvailable;
private UserBinaryDictionary mUserDictionary;
private UserHistoryPredictionDictionary mUserHistoryPredictionDictionary;
+ private PersonalizationPredictionDictionary mPersonalizationPredictionDictionary;
private boolean mIsUserDictionaryAvailable;
private LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
@@ -560,6 +562,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mUserHistoryPredictionDictionary = PersonalizationDictionaryHelper
.getUserHistoryPredictionDictionary(this, localeStr, prefs);
newSuggest.setUserHistoryPredictionDictionary(mUserHistoryPredictionDictionary);
+ mPersonalizationPredictionDictionary = PersonalizationDictionaryHelper
+ .getPersonalizationPredictionDictionary(this, localeStr, prefs);
+ newSuggest.setPersonalizationPredictionDictionary(mPersonalizationPredictionDictionary);
final Suggest oldSuggest = mSuggest;
resetContactsDictionary(null != oldSuggest ? oldSuggest.getContactsDictionary() : null);
@@ -2509,9 +2514,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final SettingsValues currentSettings = mSettings.getCurrent();
if (!currentSettings.mCorrectionEnabled) return null;
- final UserHistoryPredictionDictionary userHistoryDictionary =
+ final UserHistoryPredictionDictionary userHistoryPredictionDictionary =
mUserHistoryPredictionDictionary;
- if (userHistoryDictionary == null) return null;
+ if (userHistoryPredictionDictionary == null) return null;
final String prevWord = mConnection.getNthPreviousWord(currentSettings.mWordSeparators, 2);
final String secondWord;
@@ -2525,7 +2530,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
final int maxFreq = AutoCorrectionUtils.getMaxFrequency(
suggest.getUnigramDictionaries(), suggestion);
if (maxFreq == 0) return null;
- userHistoryDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0);
+ userHistoryPredictionDictionary.addToUserHistory(prevWord, secondWord, maxFreq > 0);
return prevWord;
}
diff --git a/java/src/com/android/inputmethod/latin/Suggest.java b/java/src/com/android/inputmethod/latin/Suggest.java
index 6b016675a..2879e2e32 100644
--- a/java/src/com/android/inputmethod/latin/Suggest.java
+++ b/java/src/com/android/inputmethod/latin/Suggest.java
@@ -22,6 +22,7 @@ import android.text.TextUtils;
import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.keyboard.ProximityInfo;
import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
+import com.android.inputmethod.latin.personalization.PersonalizationPredictionDictionary;
import com.android.inputmethod.latin.personalization.UserHistoryPredictionDictionary;
import com.android.inputmethod.latin.utils.AutoCorrectionUtils;
import com.android.inputmethod.latin.utils.BoundedTreeSet;
@@ -174,6 +175,12 @@ public final class Suggest {
userHistoryPredictionDictionary);
}
+ public void setPersonalizationPredictionDictionary(
+ final PersonalizationPredictionDictionary personalizationPredictionDictionary) {
+ addOrReplaceDictionary(mDictionaries, Dictionary.TYPE_PERSONALIZATION_PREDICTION_IN_JAVA,
+ personalizationPredictionDictionary);
+ }
+
public void setAutoCorrectionThreshold(float threshold) {
mAutoCorrectionThreshold = threshold;
}
diff --git a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
index f5dae99ef..9f013df1c 100644
--- a/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
+++ b/java/src/com/android/inputmethod/latin/personalization/PersonalizationDictionaryHelper.java
@@ -30,25 +30,52 @@ public class PersonalizationDictionaryHelper {
private static final boolean DEBUG = false;
private static final ConcurrentHashMap<String, SoftReference<UserHistoryPredictionDictionary>>
- sLangDictCache = CollectionUtils.newConcurrentHashMap();
+ sLangUserHistoryDictCache = CollectionUtils.newConcurrentHashMap();
+
+ private static final ConcurrentHashMap<String,
+ SoftReference<PersonalizationPredictionDictionary>>
+ sLangPersonalizationDictCache = CollectionUtils.newConcurrentHashMap();
public static UserHistoryPredictionDictionary getUserHistoryPredictionDictionary(
final Context context, final String locale, final SharedPreferences sp) {
- synchronized (sLangDictCache) {
- if (sLangDictCache.containsKey(locale)) {
+ synchronized (sLangUserHistoryDictCache) {
+ if (sLangUserHistoryDictCache.containsKey(locale)) {
final SoftReference<UserHistoryPredictionDictionary> ref =
- sLangDictCache.get(locale);
+ sLangUserHistoryDictCache.get(locale);
final UserHistoryPredictionDictionary dict = ref == null ? null : ref.get();
if (dict != null) {
if (DEBUG) {
- Log.w(TAG, "Use cached UserHistoryDictionary for " + locale);
+ Log.w(TAG, "Use cached UserHistoryPredictionDictionary for " + locale);
}
return dict;
}
}
final UserHistoryPredictionDictionary dict =
new UserHistoryPredictionDictionary(context, locale, sp);
- sLangDictCache.put(locale, new SoftReference<UserHistoryPredictionDictionary>(dict));
+ sLangUserHistoryDictCache.put(
+ locale, new SoftReference<UserHistoryPredictionDictionary>(dict));
+ return dict;
+ }
+ }
+
+ public static PersonalizationPredictionDictionary getPersonalizationPredictionDictionary(
+ final Context context, final String locale, final SharedPreferences sp) {
+ synchronized (sLangPersonalizationDictCache) {
+ if (sLangPersonalizationDictCache.containsKey(locale)) {
+ final SoftReference<PersonalizationPredictionDictionary> ref =
+ sLangPersonalizationDictCache.get(locale);
+ final PersonalizationPredictionDictionary dict = ref == null ? null : ref.get();
+ if (dict != null) {
+ if (DEBUG) {
+ Log.w(TAG, "Use cached PersonalizationPredictionDictionary for " + locale);
+ }
+ return dict;
+ }
+ }
+ final PersonalizationPredictionDictionary dict =
+ new PersonalizationPredictionDictionary(context, locale, sp);
+ sLangPersonalizationDictCache.put(
+ locale, new SoftReference<PersonalizationPredictionDictionary>(dict));
return dict;
}
}
diff --git a/java/src/com/android/inputmethod/research/ResearchLogger.java b/java/src/com/android/inputmethod/research/ResearchLogger.java
index fc8615b71..25187ced1 100644
--- a/java/src/com/android/inputmethod/research/ResearchLogger.java
+++ b/java/src/com/android/inputmethod/research/ResearchLogger.java
@@ -1066,22 +1066,24 @@ public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChang
private static final LogStatement LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT =
new LogStatement("MotionEvent", true, false, "action",
LogStatement.KEY_IS_LOGGING_RELATED, "motionEvent");
- public static void mainKeyboardView_processMotionEvent(final MotionEvent me, final int action,
- final long eventTime, final int index, final int id, final int x, final int y) {
- if (me != null) {
- final String actionString = LoggingUtils.getMotionEventActionTypeString(action);
- final ResearchLogger researchLogger = getInstance();
- researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
- actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me));
- if (action == MotionEvent.ACTION_DOWN) {
- // Subtract 1 from eventTime so the down event is included in the later
- // LogUnit, not the earlier (the test is for inequality).
- researchLogger.setSavedDownEventTime(eventTime - 1);
- }
- // Refresh the timer in case we are capturing user feedback.
- if (researchLogger.isMakingUserRecording()) {
- researchLogger.resetRecordingTimer();
- }
+ public static void mainKeyboardView_processMotionEvent(final MotionEvent me) {
+ if (me == null) {
+ return;
+ }
+ final int action = me.getActionMasked();
+ final long eventTime = me.getEventTime();
+ final String actionString = LoggingUtils.getMotionEventActionTypeString(action);
+ final ResearchLogger researchLogger = getInstance();
+ researchLogger.enqueueEvent(LOGSTATEMENT_MAIN_KEYBOARD_VIEW_PROCESS_MOTION_EVENT,
+ actionString, false /* IS_LOGGING_RELATED */, MotionEvent.obtain(me));
+ if (action == MotionEvent.ACTION_DOWN) {
+ // Subtract 1 from eventTime so the down event is included in the later
+ // LogUnit, not the earlier (the test is for inequality).
+ researchLogger.setSavedDownEventTime(eventTime - 1);
+ }
+ // Refresh the timer in case we are capturing user feedback.
+ if (researchLogger.isMakingUserRecording()) {
+ researchLogger.resetRecordingTimer();
}
}