[Media ML] Support customization for volume keys
Create KeyEventHandler class that is extended separately for media
and volume KeyEvents. The logic for long press and
single/double/triple taps will be the same for both KeyEvent types.
Bug: 157988289
Test: manually
Change-Id: I0df16c99d0f07714845c3324d24a804c2923ad28
(cherry picked from commit 4d7d6d83543815662791e976737fa00dbe0f11e8)
diff --git a/services/core/java/com/android/server/media/MediaKeyDispatcher.java b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
index 176ec3f..5933723 100644
--- a/services/core/java/com/android/server/media/MediaKeyDispatcher.java
+++ b/services/core/java/com/android/server/media/MediaKeyDispatcher.java
@@ -71,6 +71,9 @@
mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_STOP, 0);
mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_NEXT, 0);
mOverriddenKeyEvents.put(KeyEvent.KEYCODE_MEDIA_PREVIOUS, 0);
+ mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_DOWN, 0);
+ mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_UP, 0);
+ mOverriddenKeyEvents.put(KeyEvent.KEYCODE_VOLUME_MUTE, 0);
}
// TODO: Move this method into SessionPolicyProvider.java for better readability.
@@ -126,6 +129,9 @@
* <li> {@link KeyEvent#KEYCODE_MEDIA_STOP}
* <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT}
* <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_UP}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE}
* </ul>
* @see {@link KeyEvent#isMediaSessionKey(int)}
*/
@@ -164,6 +170,9 @@
* <li> {@link KeyEvent#KEYCODE_MEDIA_STOP}
* <li> {@link KeyEvent#KEYCODE_MEDIA_NEXT}
* <li> {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_DOWN}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_UP}
+ * <li> {@link KeyEvent#KEYCODE_VOLUME_MUTE}
* </ul>
* @see {@link KeyEvent#isMediaSessionKey(int)}
* @param keyCode
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index afae20d..9625041 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -830,9 +830,6 @@
private IOnVolumeKeyLongPressListener mOnVolumeKeyLongPressListener;
private int mOnVolumeKeyLongPressListenerUid;
- private KeyEvent mInitialDownVolumeKeyEvent;
- private int mInitialDownVolumeStream;
- private boolean mInitialDownMusicOnly;
private IOnMediaKeyListener mOnMediaKeyListener;
private int mOnMediaKeyListenerUid;
@@ -1104,12 +1101,10 @@
"android.media.AudioService.WAKELOCK_ACQUIRED";
private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
- private KeyEvent mTrackingFirstDownKeyEvent = null;
- private boolean mIsLongPressing = false;
- private Runnable mLongPressTimeoutRunnable = null;
- private int mMultiTapCount = 0;
- private int mMultiTapKeyCode = 0;
- private Runnable mMultiTapTimeoutRunnable = null;
+ private KeyEventHandler mMediaKeyEventHandler =
+ new KeyEventHandler(KeyEventHandler.KEY_TYPE_MEDIA);
+ private KeyEventHandler mVolumeKeyEventHandler =
+ new KeyEventHandler(KeyEventHandler.KEY_TYPE_VOLUME);
@Override
public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
@@ -1387,8 +1382,8 @@
dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
keyEvent, needWakeLock);
} else {
- handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
- needWakeLock);
+ mMediaKeyEventHandler.handleMediaKeyEventLocked(packageName, pid, uid,
+ asSystemService, keyEvent, needWakeLock);
}
}
} finally {
@@ -1710,53 +1705,14 @@
try {
synchronized (mLock) {
- if (isGlobalPriorityActiveLocked()
- || mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+ if (isGlobalPriorityActiveLocked()) {
dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
asSystemService, keyEvent, stream, musicOnly);
} else {
// TODO: Consider the case when both volume up and down keys are pressed
// at the same time.
- if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
- if (keyEvent.getRepeatCount() == 0) {
- // Keeps the copy of the KeyEvent because it can be reused.
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent =
- KeyEvent.obtain(keyEvent);
- mCurrentFullUserRecord.mInitialDownVolumeStream = stream;
- mCurrentFullUserRecord.mInitialDownMusicOnly = musicOnly;
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(
- MessageHandler.MSG_VOLUME_INITIAL_DOWN,
- mCurrentFullUserRecord.mFullUserId, 0),
- LONG_PRESS_TIMEOUT);
- }
- if (keyEvent.getRepeatCount() > 0 || keyEvent.isLongPress()) {
- mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
- if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null) {
- dispatchVolumeKeyLongPressLocked(
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent);
- // Mark that the key is already handled.
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent = null;
- }
- dispatchVolumeKeyLongPressLocked(keyEvent);
- }
- } else { // if up
- mHandler.removeMessages(MessageHandler.MSG_VOLUME_INITIAL_DOWN);
- if (mCurrentFullUserRecord.mInitialDownVolumeKeyEvent != null
- && mCurrentFullUserRecord.mInitialDownVolumeKeyEvent
- .getDownTime() == keyEvent.getDownTime()) {
- // Short-press. Should change volume.
- dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
- asSystemService,
- mCurrentFullUserRecord.mInitialDownVolumeKeyEvent,
- mCurrentFullUserRecord.mInitialDownVolumeStream,
- mCurrentFullUserRecord.mInitialDownMusicOnly);
- dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
- asSystemService, keyEvent, stream, musicOnly);
- } else {
- dispatchVolumeKeyLongPressLocked(keyEvent);
- }
- }
+ mVolumeKeyEventHandler.handleVolumeKeyEventLocked(packageName, pid, uid,
+ asSystemService, keyEvent, opPackageName, stream, musicOnly);
}
}
} finally {
@@ -2136,266 +2092,6 @@
}
}
- // A long press is determined by:
- // 1) A KeyEvent.ACTION_DOWN KeyEvent and repeat count of 0, followed by
- // 2) A KeyEvent.ACTION_DOWN KeyEvent with the same key code, a repeat count of 1, and
- // FLAG_LONG_PRESS received within ViewConfiguration.getLongPressTimeout().
- // A tap is determined by:
- // 1) A KeyEvent.ACTION_DOWN KeyEvent followed by
- // 2) A KeyEvent.ACTION_UP KeyEvent with the same key code.
- private void handleKeyEventLocked(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- if (keyEvent.isCanceled()) {
- return;
- }
-
- int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
- : mCustomMediaKeyDispatcher.getOverriddenKeyEvents().get(keyEvent.getKeyCode());
- cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent, needWakeLock,
- overriddenKeyEvents);
- if (!needTracking(keyEvent, overriddenKeyEvents)) {
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
- needWakeLock);
- return;
- }
-
- if (isFirstDownKeyEvent(keyEvent)) {
- mTrackingFirstDownKeyEvent = keyEvent;
- mIsLongPressing = false;
- return;
- }
-
- // Long press is always overridden here, otherwise the key event would have been already
- // handled
- if (isFirstLongPressKeyEvent(keyEvent)) {
- mIsLongPressing = true;
- }
- if (mIsLongPressing) {
- handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
- return;
- }
-
- if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
- mTrackingFirstDownKeyEvent = null;
- if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
- if (mMultiTapCount == 0) {
- mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid, uid,
- asSystemService, keyEvent, needWakeLock,
- isSingleTapOverridden(overriddenKeyEvents));
- if (isSingleTapOverridden(overriddenKeyEvents)
- && !isDoubleTapOverridden(overriddenKeyEvents)
- && !isTripleTapOverridden(overriddenKeyEvents)) {
- mMultiTapTimeoutRunnable.run();
- } else {
- mHandler.postDelayed(mMultiTapTimeoutRunnable,
- MULTI_TAP_TIMEOUT);
- mMultiTapCount = 1;
- mMultiTapKeyCode = keyEvent.getKeyCode();
- }
- } else if (mMultiTapCount == 1) {
- mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
- mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid, uid,
- asSystemService, keyEvent, needWakeLock,
- isSingleTapOverridden(overriddenKeyEvents),
- isDoubleTapOverridden(overriddenKeyEvents));
- if (isTripleTapOverridden(overriddenKeyEvents)) {
- mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
- mMultiTapCount = 2;
- } else {
- mMultiTapTimeoutRunnable.run();
- }
- } else if (mMultiTapCount == 2) {
- mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
- onTripleTap(keyEvent);
- }
- } else {
- dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
- }
- }
-
- private boolean shouldTrackForMultipleTapsLocked(int overriddenKeyEvents) {
- return isSingleTapOverridden(overriddenKeyEvents)
- || isDoubleTapOverridden(overriddenKeyEvents)
- || isTripleTapOverridden(overriddenKeyEvents);
- }
-
- private void cancelTrackingIfNeeded(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
- int overriddenKeyEvents) {
- if (mTrackingFirstDownKeyEvent == null && mMultiTapTimeoutRunnable == null) {
- return;
- }
-
- if (isFirstDownKeyEvent(keyEvent)) {
- if (mLongPressTimeoutRunnable != null) {
- mHandler.removeCallbacks(mLongPressTimeoutRunnable);
- mLongPressTimeoutRunnable.run();
- }
- if (mMultiTapTimeoutRunnable != null && keyEvent.getKeyCode() != mMultiTapKeyCode) {
- runExistingMultiTapRunnableLocked();
- }
- resetLongPressTracking();
- return;
- }
-
- if (mTrackingFirstDownKeyEvent != null
- && mTrackingFirstDownKeyEvent.getDownTime() == keyEvent.getDownTime()
- && mTrackingFirstDownKeyEvent.getKeyCode() == keyEvent.getKeyCode()
- && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
- if (isFirstLongPressKeyEvent(keyEvent)) {
- if (mMultiTapTimeoutRunnable != null) {
- runExistingMultiTapRunnableLocked();
- }
- if ((overriddenKeyEvents & KEY_EVENT_LONG_PRESS) == 0
- && !isVoiceKey(keyEvent.getKeyCode())) {
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- mTrackingFirstDownKeyEvent, needWakeLock);
- mTrackingFirstDownKeyEvent = null;
- }
- } else if (keyEvent.getRepeatCount() > 1 && !mIsLongPressing) {
- resetLongPressTracking();
- }
- }
- }
-
- private boolean needTracking(KeyEvent keyEvent, int overriddenKeyEvents) {
- if (!isFirstDownKeyEvent(keyEvent)) {
- if (mTrackingFirstDownKeyEvent == null) {
- return false;
- } else if (mTrackingFirstDownKeyEvent.getDownTime() != keyEvent.getDownTime()
- || mTrackingFirstDownKeyEvent.getKeyCode() != keyEvent.getKeyCode()) {
- return false;
- }
- }
- if (overriddenKeyEvents == 0 && !isVoiceKey(keyEvent.getKeyCode())) {
- return false;
- }
- return true;
- }
-
- private void runExistingMultiTapRunnableLocked() {
- mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
- mMultiTapTimeoutRunnable.run();
- }
-
- private void resetMultiTapTrackingLocked() {
- mMultiTapCount = 0;
- mMultiTapTimeoutRunnable = null;
- mMultiTapKeyCode = 0;
- }
-
- private void handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock,
- int overriddenKeyEvents) {
- if (mCustomMediaKeyDispatcher != null
- && isLongPressOverridden(overriddenKeyEvents)) {
- mCustomMediaKeyDispatcher.onLongPress(keyEvent);
-
- if (mLongPressTimeoutRunnable != null) {
- mHandler.removeCallbacks(mLongPressTimeoutRunnable);
- }
- if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
- if (mLongPressTimeoutRunnable == null) {
- mLongPressTimeoutRunnable = createLongPressTimeoutRunnable(keyEvent);
- }
- mHandler.postDelayed(mLongPressTimeoutRunnable, LONG_PRESS_TIMEOUT);
- } else {
- resetLongPressTracking();
- }
- } else if (isFirstLongPressKeyEvent(keyEvent) && isVoiceKey(keyEvent.getKeyCode())) {
- // Default implementation
- startVoiceInput(needWakeLock);
- resetLongPressTracking();
- }
- }
-
- private Runnable createLongPressTimeoutRunnable(KeyEvent keyEvent) {
- return new Runnable() {
- @Override
- public void run() {
- if (mCustomMediaKeyDispatcher != null) {
- mCustomMediaKeyDispatcher.onLongPress(createCanceledKeyEvent(keyEvent));
- }
- resetLongPressTracking();
- }
- };
- }
-
- private void resetLongPressTracking() {
- mTrackingFirstDownKeyEvent = null;
- mIsLongPressing = false;
- mLongPressTimeoutRunnable = null;
- }
-
- private KeyEvent createCanceledKeyEvent(KeyEvent keyEvent) {
- KeyEvent upEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
- return KeyEvent.changeTimeRepeat(upEvent, System.currentTimeMillis(), 0,
- KeyEvent.FLAG_CANCELED);
- }
-
- private boolean isFirstLongPressKeyEvent(KeyEvent keyEvent) {
- return ((keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0)
- && keyEvent.getRepeatCount() == 1;
- }
-
- private boolean isFirstDownKeyEvent(KeyEvent keyEvent) {
- return keyEvent.getAction() == KeyEvent.ACTION_DOWN && keyEvent.getRepeatCount() == 0;
- }
-
- private void dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
- KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- downEvent, needWakeLock);
- dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
-
- Runnable createSingleTapRunnable(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
- boolean overridden) {
- return new Runnable() {
- @Override
- public void run() {
- resetMultiTapTrackingLocked();
- if (overridden) {
- mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
- } else {
- dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
- }
- };
- };
-
- Runnable createDoubleTapRunnable(String packageName, int pid, int uid,
- boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
- boolean singleTapOverridden, boolean doubleTapOverridden) {
- return new Runnable() {
- @Override
- public void run() {
- resetMultiTapTrackingLocked();
- if (doubleTapOverridden) {
- mCustomMediaKeyDispatcher.onDoubleTap(keyEvent);
- } else if (singleTapOverridden) {
- mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
- mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
- } else {
- dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
- keyEvent, needWakeLock);
- }
- }
- };
- };
-
- private void onTripleTap(KeyEvent keyEvent) {
- resetMultiTapTrackingLocked();
- mCustomMediaKeyDispatcher.onTripleTap(keyEvent);
- }
-
private void dispatchMediaKeyEventLocked(String packageName, int pid, int uid,
boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
if (mCurrentFullUserRecord.getMediaButtonSessionLocked()
@@ -2579,8 +2275,8 @@
dispatchMediaKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
mKeyEvent, mNeedWakeLock);
} else {
- handleKeyEventLocked(mPackageName, mPid, mUid, mAsSystemService,
- mKeyEvent, mNeedWakeLock);
+ mMediaKeyEventHandler.handleMediaKeyEventLocked(mPackageName, mPid, mUid,
+ mAsSystemService, mKeyEvent, mNeedWakeLock);
}
}
}
@@ -2655,12 +2351,338 @@
onReceiveResult(resultCode, null);
}
};
+
+ // A long press is determined by:
+ // 1) A KeyEvent.ACTION_DOWN KeyEvent and repeat count of 0, followed by
+ // 2) A KeyEvent.ACTION_DOWN KeyEvent with the same key code, a repeat count of 1, and
+ // FLAG_LONG_PRESS received within ViewConfiguration.getLongPressTimeout().
+ // A tap is determined by:
+ // 1) A KeyEvent.ACTION_DOWN KeyEvent followed by
+ // 2) A KeyEvent.ACTION_UP KeyEvent with the same key code.
+ class KeyEventHandler {
+ private static final int KEY_TYPE_MEDIA = 0;
+ private static final int KEY_TYPE_VOLUME = 1;
+
+ private KeyEvent mTrackingFirstDownKeyEvent;
+ private boolean mIsLongPressing;
+ private Runnable mLongPressTimeoutRunnable;
+ private int mMultiTapCount;
+ private Runnable mMultiTapTimeoutRunnable;
+ private int mMultiTapKeyCode;
+ private int mKeyType;
+
+ KeyEventHandler(int keyType) {
+ mKeyType = keyType;
+ }
+
+ void handleMediaKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock) {
+ handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, needWakeLock,
+ null, 0, false);
+ }
+
+ void handleVolumeKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, String opPackageName, int stream,
+ boolean musicOnly) {
+ handleKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent, false,
+ opPackageName, stream, musicOnly);
+ }
+
+ void handleKeyEventLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+ String opPackageName, int stream, boolean musicOnly) {
+ if (keyEvent.isCanceled()) {
+ return;
+ }
+
+ int overriddenKeyEvents = (mCustomMediaKeyDispatcher == null) ? 0
+ : mCustomMediaKeyDispatcher.getOverriddenKeyEvents()
+ .get(keyEvent.getKeyCode());
+ cancelTrackingIfNeeded(packageName, pid, uid, asSystemService, keyEvent,
+ needWakeLock, opPackageName, stream, musicOnly, overriddenKeyEvents);
+ if (!needTracking(keyEvent, overriddenKeyEvents)) {
+ if (mKeyType == KEY_TYPE_VOLUME) {
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
+ } else {
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
+ }
+ return;
+ }
+
+ if (isFirstDownKeyEvent(keyEvent)) {
+ mTrackingFirstDownKeyEvent = keyEvent;
+ mIsLongPressing = false;
+ return;
+ }
+
+ // Long press is always overridden here, otherwise the key event would have been
+ // already handled
+ if (isFirstLongPressKeyEvent(keyEvent)) {
+ mIsLongPressing = true;
+ }
+ if (mIsLongPressing) {
+ handleLongPressLocked(keyEvent, needWakeLock, overriddenKeyEvents);
+ return;
+ }
+
+ if (keyEvent.getAction() == KeyEvent.ACTION_UP) {
+ mTrackingFirstDownKeyEvent = null;
+ if (shouldTrackForMultipleTapsLocked(overriddenKeyEvents)) {
+ if (mMultiTapCount == 0) {
+ mMultiTapTimeoutRunnable = createSingleTapRunnable(packageName, pid,
+ uid, asSystemService, keyEvent, needWakeLock,
+ opPackageName, stream, musicOnly,
+ isSingleTapOverridden(overriddenKeyEvents));
+ if (isSingleTapOverridden(overriddenKeyEvents)
+ && !isDoubleTapOverridden(overriddenKeyEvents)
+ && !isTripleTapOverridden(overriddenKeyEvents)) {
+ mMultiTapTimeoutRunnable.run();
+ } else {
+ mHandler.postDelayed(mMultiTapTimeoutRunnable,
+ MULTI_TAP_TIMEOUT);
+ mMultiTapCount = 1;
+ mMultiTapKeyCode = keyEvent.getKeyCode();
+ }
+ } else if (mMultiTapCount == 1) {
+ mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+ mMultiTapTimeoutRunnable = createDoubleTapRunnable(packageName, pid,
+ uid, asSystemService, keyEvent, needWakeLock, opPackageName,
+ stream, musicOnly, isSingleTapOverridden(overriddenKeyEvents),
+ isDoubleTapOverridden(overriddenKeyEvents));
+ if (isTripleTapOverridden(overriddenKeyEvents)) {
+ mHandler.postDelayed(mMultiTapTimeoutRunnable, MULTI_TAP_TIMEOUT);
+ mMultiTapCount = 2;
+ } else {
+ mMultiTapTimeoutRunnable.run();
+ }
+ } else if (mMultiTapCount == 2) {
+ mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+ onTripleTap(keyEvent);
+ }
+ } else {
+ dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+ }
+ }
+ }
+
+ private boolean shouldTrackForMultipleTapsLocked(int overriddenKeyEvents) {
+ return isSingleTapOverridden(overriddenKeyEvents)
+ || isDoubleTapOverridden(overriddenKeyEvents)
+ || isTripleTapOverridden(overriddenKeyEvents);
+ }
+
+ private void cancelTrackingIfNeeded(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+ String opPackageName, int stream, boolean musicOnly, int overriddenKeyEvents) {
+ if (mTrackingFirstDownKeyEvent == null && mMultiTapTimeoutRunnable == null) {
+ return;
+ }
+
+ if (isFirstDownKeyEvent(keyEvent)) {
+ if (mLongPressTimeoutRunnable != null) {
+ mHandler.removeCallbacks(mLongPressTimeoutRunnable);
+ mLongPressTimeoutRunnable.run();
+ }
+ if (mMultiTapTimeoutRunnable != null
+ && keyEvent.getKeyCode() != mMultiTapKeyCode) {
+ runExistingMultiTapRunnableLocked();
+ }
+ resetLongPressTracking();
+ return;
+ }
+
+ if (mTrackingFirstDownKeyEvent != null
+ && mTrackingFirstDownKeyEvent.getDownTime() == keyEvent.getDownTime()
+ && mTrackingFirstDownKeyEvent.getKeyCode() == keyEvent.getKeyCode()
+ && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+ if (isFirstLongPressKeyEvent(keyEvent)) {
+ if (mMultiTapTimeoutRunnable != null) {
+ runExistingMultiTapRunnableLocked();
+ }
+ if ((overriddenKeyEvents & KEY_EVENT_LONG_PRESS) == 0) {
+ if (mKeyType == KEY_TYPE_VOLUME) {
+ if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid,
+ uid, asSystemService, keyEvent, stream, musicOnly);
+ mTrackingFirstDownKeyEvent = null;
+ }
+ } else if (!isVoiceKey(keyEvent.getKeyCode())) {
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock);
+ mTrackingFirstDownKeyEvent = null;
+ }
+ }
+ } else if (keyEvent.getRepeatCount() > 1 && !mIsLongPressing) {
+ resetLongPressTracking();
+ }
+ }
+ }
+
+ private boolean needTracking(KeyEvent keyEvent, int overriddenKeyEvents) {
+ if (!isFirstDownKeyEvent(keyEvent)) {
+ if (mTrackingFirstDownKeyEvent == null) {
+ return false;
+ } else if (mTrackingFirstDownKeyEvent.getDownTime() != keyEvent.getDownTime()
+ || mTrackingFirstDownKeyEvent.getKeyCode() != keyEvent.getKeyCode()) {
+ return false;
+ }
+ }
+ if (overriddenKeyEvents == 0) {
+ if (mKeyType == KEY_TYPE_VOLUME) {
+ if (mCurrentFullUserRecord.mOnVolumeKeyLongPressListener == null) {
+ return false;
+ }
+ } else if (!isVoiceKey(keyEvent.getKeyCode())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private void runExistingMultiTapRunnableLocked() {
+ mHandler.removeCallbacks(mMultiTapTimeoutRunnable);
+ mMultiTapTimeoutRunnable.run();
+ }
+
+ private void resetMultiTapTrackingLocked() {
+ mMultiTapCount = 0;
+ mMultiTapTimeoutRunnable = null;
+ mMultiTapKeyCode = 0;
+ }
+
+ private void handleLongPressLocked(KeyEvent keyEvent, boolean needWakeLock,
+ int overriddenKeyEvents) {
+ if (mCustomMediaKeyDispatcher != null
+ && isLongPressOverridden(overriddenKeyEvents)) {
+ mCustomMediaKeyDispatcher.onLongPress(keyEvent);
+
+ if (mLongPressTimeoutRunnable != null) {
+ mHandler.removeCallbacks(mLongPressTimeoutRunnable);
+ }
+ if (keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
+ if (mLongPressTimeoutRunnable == null) {
+ mLongPressTimeoutRunnable = createLongPressTimeoutRunnable(keyEvent);
+ }
+ mHandler.postDelayed(mLongPressTimeoutRunnable, LONG_PRESS_TIMEOUT);
+ } else {
+ resetLongPressTracking();
+ }
+ } else {
+ if (mKeyType == KEY_TYPE_VOLUME) {
+ dispatchVolumeKeyLongPressLocked(keyEvent);
+ } else if (isFirstLongPressKeyEvent(keyEvent)
+ && isVoiceKey(keyEvent.getKeyCode())) {
+ // Default implementation
+ startVoiceInput(needWakeLock);
+ resetLongPressTracking();
+ }
+ }
+ }
+
+ private Runnable createLongPressTimeoutRunnable(KeyEvent keyEvent) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ if (mCustomMediaKeyDispatcher != null) {
+ mCustomMediaKeyDispatcher.onLongPress(createCanceledKeyEvent(keyEvent));
+ }
+ resetLongPressTracking();
+ }
+ };
+ }
+
+ private void resetLongPressTracking() {
+ mTrackingFirstDownKeyEvent = null;
+ mIsLongPressing = false;
+ mLongPressTimeoutRunnable = null;
+ }
+
+ private KeyEvent createCanceledKeyEvent(KeyEvent keyEvent) {
+ KeyEvent upEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
+ return KeyEvent.changeTimeRepeat(upEvent, System.currentTimeMillis(), 0,
+ KeyEvent.FLAG_CANCELED);
+ }
+
+ private boolean isFirstLongPressKeyEvent(KeyEvent keyEvent) {
+ return ((keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0)
+ && keyEvent.getRepeatCount() == 1;
+ }
+
+ private boolean isFirstDownKeyEvent(KeyEvent keyEvent) {
+ return keyEvent.getAction() == KeyEvent.ACTION_DOWN
+ && keyEvent.getRepeatCount() == 0;
+ }
+
+ private void dispatchDownAndUpKeyEventsLocked(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+ String opPackageName, int stream, boolean musicOnly) {
+ KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
+ if (mKeyType == KEY_TYPE_VOLUME) {
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, downEvent, stream, musicOnly);
+ dispatchVolumeKeyEventLocked(packageName, opPackageName, pid, uid,
+ asSystemService, keyEvent, stream, musicOnly);
+ } else {
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, downEvent,
+ needWakeLock);
+ dispatchMediaKeyEventLocked(packageName, pid, uid, asSystemService, keyEvent,
+ needWakeLock);
+ }
+ }
+
+ Runnable createSingleTapRunnable(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+ String opPackageName, int stream, boolean musicOnly, boolean overridden) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ resetMultiTapTrackingLocked();
+ if (overridden) {
+ mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+ } else {
+ dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+ }
+ }
+ };
+ };
+
+ Runnable createDoubleTapRunnable(String packageName, int pid, int uid,
+ boolean asSystemService, KeyEvent keyEvent, boolean needWakeLock,
+ String opPackageName, int stream, boolean musicOnly,
+ boolean singleTapOverridden, boolean doubleTapOverridden) {
+ return new Runnable() {
+ @Override
+ public void run() {
+ resetMultiTapTrackingLocked();
+ if (doubleTapOverridden) {
+ mCustomMediaKeyDispatcher.onDoubleTap(keyEvent);
+ } else if (singleTapOverridden) {
+ mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+ mCustomMediaKeyDispatcher.onSingleTap(keyEvent);
+ } else {
+ dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+ dispatchDownAndUpKeyEventsLocked(packageName, pid, uid, asSystemService,
+ keyEvent, needWakeLock, opPackageName, stream, musicOnly);
+ }
+ }
+ };
+ };
+
+ private void onTripleTap(KeyEvent keyEvent) {
+ resetMultiTapTrackingLocked();
+ mCustomMediaKeyDispatcher.onTripleTap(keyEvent);
+ }
+ }
}
final class MessageHandler extends Handler {
private static final int MSG_SESSIONS_1_CHANGED = 1;
private static final int MSG_SESSIONS_2_CHANGED = 2;
- private static final int MSG_VOLUME_INITIAL_DOWN = 3;
private final SparseArray<Integer> mIntegerCache = new SparseArray<>();
@Override
@@ -2672,16 +2694,6 @@
case MSG_SESSIONS_2_CHANGED:
pushSession2Changed((int) msg.obj);
break;
- case MSG_VOLUME_INITIAL_DOWN:
- synchronized (mLock) {
- FullUserRecord user = mUserRecords.get((int) msg.arg1);
- if (user != null && user.mInitialDownVolumeKeyEvent != null) {
- dispatchVolumeKeyLongPressLocked(user.mInitialDownVolumeKeyEvent);
- // Mark that the key is already handled.
- user.mInitialDownVolumeKeyEvent = null;
- }
- }
- break;
}
}