Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9580c467 authored by Tadashi G. Takaoka's avatar Tadashi G. Takaoka
Browse files

Consolidate GestureTracker into PointerTracker

Change-Id: Ib28fae10493a9142ba4dff6cf57f52c59766b209
parent 10102f02
Loading
Loading
Loading
Loading
+109 −49
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import android.view.View;
import android.widget.TextView;

import com.android.inputmethod.keyboard.internal.GestureStroke;
import com.android.inputmethod.keyboard.internal.GestureTracker;
import com.android.inputmethod.keyboard.internal.PointerTrackerQueue;
import com.android.inputmethod.latin.InputPointers;
import com.android.inputmethod.latin.LatinImeLogger;
@@ -39,6 +38,10 @@ public class PointerTracker {
    private static final boolean DEBUG_LISTENER = false;
    private static boolean DEBUG_MODE = LatinImeLogger.sDBG;

    // TODO: There should be an option to turn on/off the gesture input.
    private static final boolean GESTURE_ON = true;
    private static final int MIN_RECOGNITION_TIME = 100; // msec

    public interface KeyEventHandler {
        /**
         * Get KeyDetector object that is used for this PointerTracker.
@@ -128,6 +131,13 @@ public class PointerTracker {
    private int mKeyQuarterWidthSquared;
    private final TextView mKeyPreviewText;

    private boolean mIsAlphabetKeyboard;
    private boolean mIsPossibleGesture = false;
    private boolean mInGesture = false;

    private int mLastRecognitionPointSize = 0;
    private long mLastRecognitionTime = 0;

    // The position and time at which first down event occurred.
    private long mDownTime;
    private long mUpTime;
@@ -164,9 +174,6 @@ public class PointerTracker {
    private static final KeyboardActionListener EMPTY_LISTENER =
            new KeyboardActionListener.Adapter();

    // Gesture tracker singleton instance
    private static final GestureTracker sGestureTracker = GestureTracker.getInstance();

    private final GestureStroke mGestureStroke;

    public static void init(boolean hasDistinctMultitouch,
@@ -207,7 +214,6 @@ public class PointerTracker {
        for (final PointerTracker tracker : sTrackers) {
            tracker.mListener = listener;
        }
        GestureTracker.init(listener);
    }

    public static void setKeyDetector(KeyDetector keyDetector) {
@@ -216,7 +222,6 @@ public class PointerTracker {
            // Mark that keyboard layout has been changed.
            tracker.mKeyboardLayoutHasBeenChanged = true;
        }
        sGestureTracker.setKeyboard(keyDetector.getKeyboard());
    }

    public static void dismissAllKeyPreviews() {
@@ -226,35 +231,35 @@ public class PointerTracker {
        }
    }

    // The working and returning object of the following methods,
    // {@link #getIncrementalBatchPoints()} and {@link #getAllBatchPoints()}.
    private static final InputPointers mAggregatedPointers = new InputPointers();

    // TODO: This method is called only from GestureTracker and should address the thread-safty
    // issue soon.
    public static InputPointers getIncrementalBatchPoints() {
        final InputPointers pointers = mAggregatedPointers;
        pointers.reset();
    // TODO: To handle multi-touch gestures we may want to move this method to
    // {@link PointerTrackerQueue}.
    private static InputPointers getIncrementalBatchPoints() {
        final InputPointers pointers = new InputPointers();
        // TODO: Add a default capacity parameter for the InputPointers' constructor.
        // TODO: Avoid creating a new instance here?
        for (final PointerTracker tracker : sTrackers) {
            tracker.getGestureStroke().appendIncrementalBatchPoints(pointers);
            tracker.mGestureStroke.appendIncrementalBatchPoints(pointers);
        }
        return pointers;
    }

    // TODO: This method is called only from GestureTracker and should address the thread-safety
    // issue soon.
    public static InputPointers getAllBatchPoints() {
        final InputPointers pointers = mAggregatedPointers;
        pointers.reset();
    // TODO: To handle multi-touch gestures we may want to move this method to
    // {@link PointerTrackerQueue}.
    private static InputPointers getAllBatchPoints() {
        // TODO: Add a default capacity parameter for the InputPointers' constructor.
        // TODO: Avoid creating a new instance here?
        final InputPointers pointers = new InputPointers();
        for (final PointerTracker tracker : sTrackers) {
            tracker.getGestureStroke().appendAllBatchPoints(pointers);
            tracker.mGestureStroke.appendAllBatchPoints(pointers);
        }
        return pointers;
    }

    // TODO: To handle multi-touch gestures we may want to move this method to
    // {@link PointerTrackerQueue}.
    public static void clearBatchInputPoints() {
        for (final PointerTracker tracker : sTrackers) {
            tracker.getGestureStroke().reset();
            tracker.mGestureStroke.reset();
        }
    }

@@ -274,13 +279,9 @@ public class PointerTracker {
        return mKeyPreviewText;
    }

    public GestureStroke getGestureStroke() {
        return mGestureStroke;
    }

    // Returns true if keyboard has been changed by this callback.
    private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key) {
        if (sGestureTracker.isInGesture()) {
        if (mInGesture) {
            return false;
        }
        final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
@@ -336,7 +337,7 @@ 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()) {
        if (mInGesture) {
            return;
        }
        final boolean ignoreModifierKey = mIgnoreModifierKey && key.isModifier();
@@ -369,6 +370,7 @@ public class PointerTracker {
    private void setKeyDetectorInner(KeyDetector keyDetector) {
        mKeyDetector = keyDetector;
        mKeyboard = keyDetector.getKeyboard();
        mIsAlphabetKeyboard = mKeyboard.mId.isAlphabetKeyboard();
        mGestureStroke.setGestureSampleLength(
                mKeyboard.mMostCommonKeyWidth, mKeyboard.mMostCommonKeyHeight);
        final Key newKey = mKeyDetector.detectHitKey(mKeyX, mKeyY);
@@ -441,7 +443,7 @@ public class PointerTracker {
            return;
        }

        if (!key.noKeyPreview() && !sGestureTracker.isInGesture()) {
        if (!key.noKeyPreview() && !mInGesture) {
            mDrawingProxy.showKeyPreview(this);
        }
        updatePressKeyGraphics(key);
@@ -512,6 +514,45 @@ public class PointerTracker {
        return newKey;
    }

    private void startBatchInput() {
        if (DEBUG_LISTENER) {
            Log.d(TAG, "onStartBatchInput");
        }
        mInGesture = true;
        mListener.onStartBatchInput();
    }

    private void updateBatchInput(InputPointers batchPoints) {
        if (DEBUG_LISTENER) {
            Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
        }
        mListener.onUpdateBatchInput(batchPoints);
    }

    private void endBatchInput(InputPointers batchPoints) {
        if (DEBUG_LISTENER) {
            Log.d(TAG, "onEndBatchInput: batchPoints=" + batchPoints.getPointerSize());
        }
        mListener.onEndBatchInput(batchPoints);
        mInGesture = false;
        clearBatchInputPoints();
    }

    private void abortBatchInput() {
        mIsPossibleGesture = false;
        mInGesture = false;
    }

    private boolean updateBatchInputRecognitionState(long eventTime, int size) {
        if (size > mLastRecognitionPointSize
                && eventTime > mLastRecognitionTime + MIN_RECOGNITION_TIME) {
            mLastRecognitionPointSize = size;
            mLastRecognitionTime = eventTime;
            return true;
        }
        return false;
    }

    public void processMotionEvent(int action, int x, int y, long eventTime,
            KeyEventHandler handler) {
        switch (action) {
@@ -570,7 +611,13 @@ public class PointerTracker {
        }
        onDownEventInternal(x, y, eventTime);
        if (queue != null && queue.size() == 1) {
            sGestureTracker.onDownEvent(this, x, y, eventTime, key);
            mIsPossibleGesture = false;
            // A gesture should start only from the letter key.
            if (GESTURE_ON && mIsAlphabetKeyboard && key != null
                    && Keyboard.isLetterCode(key.mCode)) {
                mIsPossibleGesture = true;
                mGestureStroke.addPoint(x, y, 0, false);
            }
        }
    }

@@ -606,6 +653,25 @@ public class PointerTracker {
        mIsInSlidingKeyInput = true;
    }

    private void onGestureMoveEvent(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 = mGestureStroke;
            stroke.addPoint(x, y, gestureTime, isHistorical);
            if (!mInGesture && stroke.isStartOfAGesture(gestureTime)) {
                startBatchInput();
            }
        }

        if (key != null && mInGesture) {
            final InputPointers batchPoints = getIncrementalBatchPoints();
            if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) {
                updateBatchInput(batchPoints);
            }
        }
    }

    public void onMoveEvent(int x, int y, long eventTime, MotionEvent me) {
        if (DEBUG_MOVE_EVENT)
            printTouchEvent("onMoveEvent:", x, y, eventTime);
@@ -620,7 +686,7 @@ public class PointerTracker {
                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,
                onGestureMoveEvent(this, historicalX, historicalY, historicalTime,
                        true /* isHistorical */, null);
            }
        }
@@ -631,8 +697,8 @@ public class PointerTracker {
        Key key = onMoveKey(x, y);

        // Register move event on gesture tracker.
        sGestureTracker.onMoveEvent(this, x, y, eventTime, false, key);
        if (sGestureTracker.isInGesture()) {
        onGestureMoveEvent(this, x, y, eventTime, false /* isHistorical */, key);
        if (mInGesture) {
            mIgnoreModifierKey = true;
            mTimerProxy.cancelLongPressTimer();
            mIsInSlidingKeyInput = true;
@@ -729,7 +795,7 @@ public class PointerTracker {

        final PointerTrackerQueue queue = sPointerTrackerQueue;
        if (queue != null) {
            if (!sGestureTracker.isInGesture()) {
            if (!mInGesture) {
                if (mCurrentKey != null && mCurrentKey.isModifier()) {
                    // Before processing an up event of modifier key, all pointers already being
                    // tracked should be released.
@@ -763,21 +829,16 @@ public class PointerTracker {
            mIsShowingMoreKeysPanel = false;
        }

        if (sGestureTracker.isInGesture()) {
        if (mInGesture) {
            // 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();
            }
            // TODO: Figure out how to deal with multiple fingers that are in gesture, sliding,
            // and/or tapping mode?
            endBatchInput(getAllBatchPoints());
            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)
@@ -791,8 +852,7 @@ 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();
        abortBatchInput();
    }

    public void onLongPressed() {
@@ -827,7 +887,7 @@ public class PointerTracker {
    }

    private void startRepeatKey(Key key) {
        if (key != null && key.isRepeatable() && !sGestureTracker.isInGesture()) {
        if (key != null && key.isRepeatable() && !mInGesture) {
            onRegisterKey(key);
            mTimerProxy.startKeyRepeatTimer(this);
        }
@@ -857,7 +917,7 @@ public class PointerTracker {
    }

    private void startLongPressTimer(Key key) {
        if (key != null && key.isLongPressEnabled() && !sGestureTracker.isInGesture()) {
        if (key != null && key.isLongPressEnabled() && !mInGesture) {
            mTimerProxy.startLongPressTimer(this);
        }
    }
+0 −147
Original line number Diff line number Diff line
/*
 * 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 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;

// 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 boolean mIsAlphabetKeyboard;
    private boolean mIsPossibleGesture = false;
    private boolean mInGesture = false;

    private KeyboardActionListener mListener;

    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();
    }

    private void startBatchInput() {
        if (DEBUG_LISTENER) {
            Log.d(TAG, "onStartBatchInput");
        }
        mInGesture = true;
        mListener.onStartBatchInput();
    }

    // TODO: The corresponding startBatchInput() is a private method. Reorganize the code.
    public void endBatchInput() {
        if (isInGesture()) {
            final InputPointers batchPoints = PointerTracker.getAllBatchPoints();
            if (DEBUG_LISTENER) {
                Log.d(TAG, "onEndBatchInput: batchPoints=" + batchPoints.getPointerSize());
            }
            mListener.onEndBatchInput(batchPoints);
        }
        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;
        // A gesture should start only from the letter key.
        if (GESTURE_ON && mIsAlphabetKeyboard && key != null && Keyboard.isLetterCode(key.mCode)) {
            mIsPossibleGesture = true;
            tracker.getGestureStroke().addPoint(x, y, 0, 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 = tracker.getGestureStroke();
            stroke.addPoint(x, y, gestureTime, isHistorical);
            if (!isInGesture() && stroke.isStartOfAGesture(gestureTime)) {
                startBatchInput();
            }
        }

        if (key != null && isInGesture()) {
            final InputPointers batchPoints = PointerTracker.getIncrementalBatchPoints();
            if (updateBatchInputRecognitionState(eventTime, batchPoints.getPointerSize())) {
                if (DEBUG_LISTENER) {
                    Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
                }
                mListener.onUpdateBatchInput(batchPoints);
            }
        }
    }

    public void onUpEvent(PointerTracker tracker, int x, int y, long eventTime) {
        if (isInGesture()) {
            final InputPointers batchPoints = PointerTracker.getAllBatchPoints();
            if (DEBUG_LISTENER) {
                Log.d(TAG, "onUpdateBatchInput: batchPoints=" + batchPoints.getPointerSize());
            }
            mListener.onUpdateBatchInput(batchPoints);
        }
    }

    private void clearBatchInputPoints() {
        PointerTracker.clearBatchInputPoints();
        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;
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -60,6 +60,9 @@ public class InputPointers {
     * @param length the number of pointers to be appended.
     */
    public void append(InputPointers src, int startPos, int length) {
        if (length == 0) {
            return;
        }
        mXCoordinates.append(src.mXCoordinates, startPos, length);
        mYCoordinates.append(src.mYCoordinates, startPos, length);
        mPointerIds.append(src.mPointerIds, startPos, length);