From e7a9ae8ba0fb7fc61960e3facd0c5534e9ffce1e Mon Sep 17 00:00:00 2001 From: Michael Wright Date: Fri, 8 Mar 2013 15:19:19 -0800 Subject: [PATCH] Add touch navigation input source Bug: 8276741 Change-Id: I674b9804bf9ae76d694ae7073b54a7d43474a43c --- api/current.txt | 2 + core/java/android/view/InputDevice.java | 20 ++++++- core/java/android/view/SimulatedDpad.java | 70 +++++++++++------------ core/java/android/view/ViewRootImpl.java | 16 +++--- services/input/InputReader.cpp | 8 +++ services/input/InputReader.h | 1 + 6 files changed, 73 insertions(+), 44 deletions(-) diff --git a/api/current.txt b/api/current.txt index 3f3819c8781ff..3132a9188f5dc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -24171,6 +24171,7 @@ package android.view { field public static final int SOURCE_CLASS_BUTTON = 1; // 0x1 field public static final int SOURCE_CLASS_JOYSTICK = 16; // 0x10 field public static final int SOURCE_CLASS_MASK = 255; // 0xff + field public static final int SOURCE_CLASS_NONE = 0; // 0x0 field public static final int SOURCE_CLASS_POINTER = 2; // 0x2 field public static final int SOURCE_CLASS_POSITION = 8; // 0x8 field public static final int SOURCE_CLASS_TRACKBALL = 4; // 0x4 @@ -24182,6 +24183,7 @@ package android.view { field public static final int SOURCE_STYLUS = 16386; // 0x4002 field public static final int SOURCE_TOUCHPAD = 1048584; // 0x100008 field public static final int SOURCE_TOUCHSCREEN = 4098; // 0x1002 + field public static final int SOURCE_TOUCH_NAVIGATION = 2097152; // 0x200000 field public static final int SOURCE_TRACKBALL = 65540; // 0x10004 field public static final int SOURCE_UNKNOWN = 0; // 0x0 } diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index c3dc76d81b99d..dd523d23ea191 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -62,7 +62,14 @@ public final class InputDevice implements Parcelable { * specify the desired interpretation for its input events. */ public static final int SOURCE_CLASS_MASK = 0x000000ff; - + + /** + * The input source has no class. + * + * It is up to the application to determine how to handle the device based on the device type. + */ + public static final int SOURCE_CLASS_NONE = 0x00000000; + /** * The input source has buttons or keys. * Examples: {@link #SOURCE_KEYBOARD}, {@link #SOURCE_DPAD}. @@ -201,6 +208,17 @@ public final class InputDevice implements Parcelable { */ public static final int SOURCE_TOUCHPAD = 0x00100000 | SOURCE_CLASS_POSITION; + /** + * The input source is a touch device whose motions should be interpreted as navigation events. + * + * For example, an upward swipe should be as an upward focus traversal in the same manner as + * pressing up on a D-Pad would be. Swipes to the left, right and down should be treated in a + * similar manner. + * + * @see #SOURCE_CLASS_NONE + */ + public static final int SOURCE_TOUCH_NAVIGATION = 0x00200000 | SOURCE_CLASS_NONE; + /** * The input source is a joystick. * (It may also be a {@link #SOURCE_GAMEPAD}). diff --git a/core/java/android/view/SimulatedDpad.java b/core/java/android/view/SimulatedDpad.java index 883fd49614e1a..c889328fb4e24 100644 --- a/core/java/android/view/SimulatedDpad.java +++ b/core/java/android/view/SimulatedDpad.java @@ -28,7 +28,7 @@ import android.os.UserHandle; import android.util.Log; /** - * This class creates DPAD events from touchpad events. + * This class creates DPAD events from TouchNavigation events. * * @see ViewRootImpl */ @@ -47,18 +47,18 @@ class SimulatedDpad { private static final int MSG_FLICK = 313; // TODO: Pass touch slop from the input device private static final int TOUCH_SLOP = 30; - // The position of the previous touchpad event - private float mLastTouchpadXPosition; - private float mLastTouchpadYPosition; - // Where the touchpad was initially pressed - private float mTouchpadEnterXPosition; - private float mTouchpadEnterYPosition; + // The position of the previous TouchNavigation event + private float mLastTouchNavigationXPosition; + private float mLastTouchNavigationYPosition; + // Where the Touch Navigation was initially pressed + private float mTouchNavigationEnterXPosition; + private float mTouchNavigationEnterYPosition; // When the most recent ACTION_HOVER_ENTER occurred - private long mLastTouchPadStartTimeMs = 0; + private long mLastTouchNavigationStartTimeMs = 0; // When the most recent direction key was sent - private long mLastTouchPadKeySendTimeMs = 0; + private long mLastTouchNavigationKeySendTimeMs = 0; // When the most recent touch event of any type occurred - private long mLastTouchPadEventTimeMs = 0; + private long mLastTouchNavigationEventTimeMs = 0; // Did the swipe begin in a valid region private boolean mEdgeSwipePossible; @@ -140,7 +140,7 @@ class SimulatedDpad { } }; - public void updateTouchPad(ViewRootImpl viewroot, MotionEvent event, + public void updateTouchNavigation(ViewRootImpl viewroot, MotionEvent event, boolean synthesizeNewKeys) { if (!synthesizeNewKeys) { mHandler.removeMessages(MSG_FLICK); @@ -149,14 +149,14 @@ class SimulatedDpad { if (device == null) { return; } - // Store what time the touchpad event occurred + // Store what time the TouchNavigation event occurred final long time = SystemClock.uptimeMillis(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: - mLastTouchPadStartTimeMs = time; + mLastTouchNavigationStartTimeMs = time; mAlwaysInTapRegion = true; - mTouchpadEnterXPosition = event.getX(); - mTouchpadEnterYPosition = event.getY(); + mTouchNavigationEnterXPosition = event.getX(); + mTouchNavigationEnterYPosition = event.getY(); mAccumulatedX = 0; mAccumulatedY = 0; mLastMoveX = 0; @@ -173,8 +173,8 @@ class SimulatedDpad { break; case MotionEvent.ACTION_MOVE: // Determine whether the move is slop or an intentional move - float deltaX = event.getX() - mTouchpadEnterXPosition; - float deltaY = event.getY() - mTouchpadEnterYPosition; + float deltaX = event.getX() - mTouchNavigationEnterXPosition; + float deltaY = event.getY() - mTouchNavigationEnterYPosition; if (mTouchSlopSquared < deltaX * deltaX + deltaY * deltaY) { mAlwaysInTapRegion = false; } @@ -199,9 +199,9 @@ class SimulatedDpad { } } // Find the difference in position between the two most recent - // touchpad events - mLastMoveX = event.getX() - mLastTouchpadXPosition; - mLastMoveY = event.getY() - mLastTouchpadYPosition; + // TouchNavigation events + mLastMoveX = event.getX() - mLastTouchNavigationXPosition; + mLastMoveY = event.getY() - mLastTouchNavigationYPosition; mAccumulatedX += mLastMoveX; mAccumulatedY += mLastMoveY; float mAccumulatedXSquared = mAccumulatedX * mAccumulatedX; @@ -251,28 +251,28 @@ class SimulatedDpad { mAccumulatedY = isXAxis ? 0 : dominantAxis; mLastKeySent = key; - mKeySendRateMs = (int) ((time - mLastTouchPadKeySendTimeMs) / repeatCount); - mLastTouchPadKeySendTimeMs = time; + mKeySendRateMs = (int) (time - mLastTouchNavigationKeySendTimeMs) / repeatCount; + mLastTouchNavigationKeySendTimeMs = time; } break; case MotionEvent.ACTION_UP: - if (time - mLastTouchPadStartTimeMs < MAX_TAP_TIME && mAlwaysInTapRegion) { + if (time - mLastTouchNavigationStartTimeMs < MAX_TAP_TIME && mAlwaysInTapRegion) { if (synthesizeNewKeys) { - viewroot.enqueueInputEvent(new KeyEvent(mLastTouchPadStartTimeMs, time, - KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, - event.getMetaState(), event.getDeviceId(), 0, - KeyEvent.FLAG_FALLBACK, event.getSource())); - viewroot.enqueueInputEvent(new KeyEvent(mLastTouchPadStartTimeMs, time, - KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, - event.getMetaState(), event.getDeviceId(), 0, - KeyEvent.FLAG_FALLBACK, event.getSource())); + viewroot.enqueueInputEvent(new KeyEvent(mLastTouchNavigationStartTimeMs, + time, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER, 0, + event.getMetaState(), event.getDeviceId(), 0, + KeyEvent.FLAG_FALLBACK, event.getSource())); + viewroot.enqueueInputEvent(new KeyEvent(mLastTouchNavigationStartTimeMs, + time, KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER, 0, + event.getMetaState(), event.getDeviceId(), 0, + KeyEvent.FLAG_FALLBACK, event.getSource())); } } else { float xMoveSquared = mLastMoveX * mLastMoveX; float yMoveSquared = mLastMoveY * mLastMoveY; // Determine whether the last gesture was a fling. if (mMinFlickDistanceSquared <= xMoveSquared + yMoveSquared && - time - mLastTouchPadEventTimeMs <= MAX_TAP_TIME && + time - mLastTouchNavigationEventTimeMs <= MAX_TAP_TIME && mKeySendRateMs <= mMaxRepeatDelay && mKeySendRateMs > 0) { mLastDeviceId = event.getDeviceId(); mLastSource = event.getSource(); @@ -291,8 +291,8 @@ class SimulatedDpad { } // Store touch event position and time - mLastTouchPadEventTimeMs = time; - mLastTouchpadXPosition = event.getX(); - mLastTouchpadYPosition = event.getY(); + mLastTouchNavigationEventTimeMs = time; + mLastTouchNavigationXPosition = event.getX(); + mLastTouchNavigationYPosition = event.getY(); } } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index b8fae865e1019..a93788215d645 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -3559,15 +3559,15 @@ public final class ViewRootImpl implements ViewParent, private int deliverGenericMotionEventPostIme(QueuedInputEvent q) { final MotionEvent event = (MotionEvent) q.mEvent; final int source = event.getSource(); - final boolean isJoystick = (source & InputDevice.SOURCE_CLASS_JOYSTICK) != 0; - final boolean isTouchPad = (source & InputDevice.SOURCE_CLASS_POSITION) != 0; + final boolean isJoystick = event.isFromSource(InputDevice.SOURCE_CLASS_JOYSTICK); + final boolean isTouchNavigation = event.isFromSource(InputDevice.SOURCE_TOUCH_NAVIGATION); // If there is no view, then the event will not be handled. if (mView == null || !mAdded) { if (isJoystick) { updateJoystickDirection(event, false); - } else if (isTouchPad) { - mSimulatedDpad.updateTouchPad(this, event, false); + } else if (isTouchNavigation) { + mSimulatedDpad.updateTouchNavigation(this, event, false); } return EVENT_NOT_HANDLED; } @@ -3576,8 +3576,8 @@ public final class ViewRootImpl implements ViewParent, if (mView.dispatchGenericMotionEvent(event)) { if (isJoystick) { updateJoystickDirection(event, false); - } else if (isTouchPad) { - mSimulatedDpad.updateTouchPad(this, event, false); + } else if (isTouchNavigation) { + mSimulatedDpad.updateTouchNavigation(this, event, false); } return EVENT_HANDLED; } @@ -3588,8 +3588,8 @@ public final class ViewRootImpl implements ViewParent, updateJoystickDirection(event, true); return EVENT_HANDLED; } - if (isTouchPad) { - mSimulatedDpad.updateTouchPad(this, event, true); + if (isTouchNavigation) { + mSimulatedDpad.updateTouchNavigation(this, event, true); return EVENT_HANDLED; } return EVENT_NOT_HANDLED; diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index bc8df184f05ff..43d76bbd9e44d 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -2788,6 +2788,8 @@ void TouchInputMapper::configureParameters() { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; } else if (deviceTypeString == "touchPad") { mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; + } else if (deviceTypeString == "touchNavigation") { + mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; } else if (deviceTypeString == "pointer") { mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; } else if (deviceTypeString != "default") { @@ -2832,6 +2834,9 @@ void TouchInputMapper::dumpParameters(String8& dump) { case Parameters::DEVICE_TYPE_TOUCH_PAD: dump.append(INDENT4 "DeviceType: touchPad\n"); break; + case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: + dump.append(INDENT4 "DeviceType: touchNavigation\n"); + break; case Parameters::DEVICE_TYPE_POINTER: dump.append(INDENT4 "DeviceType: pointer\n"); break; @@ -2885,6 +2890,9 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { if (hasStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } + } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { + mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; + mDeviceMode = DEVICE_MODE_UNSCALED; } else { mSource = AINPUT_SOURCE_TOUCHPAD; mDeviceMode = DEVICE_MODE_UNSCALED; diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 61b21e2e30dcb..c596b379049c6 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -1192,6 +1192,7 @@ protected: enum DeviceType { DEVICE_TYPE_TOUCH_SCREEN, DEVICE_TYPE_TOUCH_PAD, + DEVICE_TYPE_TOUCH_NAVIGATION, DEVICE_TYPE_POINTER, };