Add touch navigation input source
Bug: 8276741
Change-Id: I674b9804bf9ae76d694ae7073b54a7d43474a43c
diff --git a/api/current.txt b/api/current.txt
index 3f3819c..3132a91 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -24171,6 +24171,7 @@
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 @@
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 c3dc76d..dd523d2 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -62,7 +62,14 @@
* 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}.
@@ -202,6 +209,17 @@
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 883fd49..c889328 100644
--- a/core/java/android/view/SimulatedDpad.java
+++ b/core/java/android/view/SimulatedDpad.java
@@ -28,7 +28,7 @@
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 @@
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 @@
}
};
- 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 @@
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 @@
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 @@
}
}
// 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 @@
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 @@
}
// 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 b8fae865..a937882 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3559,15 +3559,15 @@
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 @@
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 @@
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 bc8df18..43d76bb 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -2788,6 +2788,8 @@
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 @@
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 @@
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 61b21e2..c596b37 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -1192,6 +1192,7 @@
enum DeviceType {
DEVICE_TYPE_TOUCH_SCREEN,
DEVICE_TYPE_TOUCH_PAD,
+ DEVICE_TYPE_TOUCH_NAVIGATION,
DEVICE_TYPE_POINTER,
};