diff options
author | Winson Chung <winsonc@google.com> | 2011-10-12 17:00:11 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2011-10-12 17:00:11 -0700 |
commit | a76a87a8efbc1e6d3d6f503d937ab18a91638ecf (patch) | |
tree | 7c1a59324d43ee2baf352aa5c319fd3662c02aed | |
parent | f838b7c2b8c4f0f1c48f315f49fea340b2b10d83 (diff) | |
parent | d5bb82d18cbd95bb9e751d8315b9ed0b69595033 (diff) | |
download | frameworks_base-a76a87a8efbc1e6d3d6f503d937ab18a91638ecf.zip frameworks_base-a76a87a8efbc1e6d3d6f503d937ab18a91638ecf.tar.gz frameworks_base-a76a87a8efbc1e6d3d6f503d937ab18a91638ecf.tar.bz2 |
Merge "DO NOT MERGE. Improve screenshot chord debouncing. Bug: 5011907" into ics-mr0
-rw-r--r-- | core/java/android/view/WindowManagerPolicy.java | 20 | ||||
-rwxr-xr-x | policy/src/com/android/internal/policy/impl/PhoneWindowManager.java | 310 | ||||
-rw-r--r-- | services/input/InputDispatcher.cpp | 29 | ||||
-rw-r--r-- | services/input/InputDispatcher.h | 4 | ||||
-rw-r--r-- | services/input/tests/InputDispatcher_test.cpp | 4 | ||||
-rw-r--r-- | services/java/com/android/server/wm/InputManager.java | 2 | ||||
-rw-r--r-- | services/java/com/android/server/wm/InputMonitor.java | 2 | ||||
-rw-r--r-- | services/jni/com_android_server_InputManager.cpp | 31 |
8 files changed, 241 insertions, 161 deletions
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index bfd2959..17bdff2 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -104,23 +104,23 @@ public interface WindowManagerPolicy { */ public final static String EXTRA_HDMI_PLUGGED_STATE = "state"; - // flags for interceptKeyTq /** - * Pass this event to the user / app. To be returned from {@link #interceptKeyTq}. + * Pass this event to the user / app. To be returned from + * {@link #interceptKeyBeforeQueueing}. */ public final static int ACTION_PASS_TO_USER = 0x00000001; /** * This key event should extend the user activity timeout and turn the lights on. - * To be returned from {@link #interceptKeyTq}. Do not return this and - * {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}. + * To be returned from {@link #interceptKeyBeforeQueueing}. + * Do not return this and {@link #ACTION_GO_TO_SLEEP} or {@link #ACTION_PASS_TO_USER}. */ public final static int ACTION_POKE_USER_ACTIVITY = 0x00000002; /** * This key event should put the device to sleep (and engage keyguard if necessary) - * To be returned from {@link #interceptKeyTq}. Do not return this and - * {@link #ACTION_POKE_USER_ACTIVITY} or {@link #ACTION_PASS_TO_USER}. + * To be returned from {@link #interceptKeyBeforeQueueing}. + * Do not return this and {@link #ACTION_POKE_USER_ACTIVITY} or {@link #ACTION_PASS_TO_USER}. */ public final static int ACTION_GO_TO_SLEEP = 0x00000004; @@ -677,10 +677,12 @@ public interface WindowManagerPolicy { * event will normally go. * @param event The key event. * @param policyFlags The policy flags associated with the key. - * @return Returns true if the policy consumed the event and it should - * not be further dispatched. + * @return 0 if the key should be dispatched immediately, -1 if the key should + * not be dispatched ever, or a positive value indicating the number of + * milliseconds by which the key dispatch should be delayed before trying + * again. */ - public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags); + public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags); /** * Called from the input dispatcher thread when an application did not handle diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 487063d..3eb04cb 100755 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -267,7 +267,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { WindowState mKeyguard = null; KeyguardViewMediator mKeyguardMediator; GlobalActions mGlobalActions; - volatile boolean mPowerKeyHandled; + volatile boolean mPowerKeyHandled; // accessed from input reader and handler thread + boolean mPendingPowerKeyUpCanceled; RecentApplicationsDialog mRecentAppsDialog; Handler mHandler; @@ -403,8 +404,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { private int mLongPressOnHomeBehavior = -1; // Screenshot trigger states - private boolean mVolumeDownTriggered; - private boolean mPowerDownTriggered; + // Time to volume and power must be pressed within this interval of each other. + private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150; + private boolean mVolumeDownKeyTriggered; + private long mVolumeDownKeyTime; + private boolean mVolumeDownKeyConsumedByScreenshotChord; + private boolean mVolumeUpKeyTriggered; + private boolean mPowerKeyTriggered; + private long mPowerKeyTime; ShortcutManager mShortcutManager; PowerManager.WakeLock mBroadcastWakeLock; @@ -552,40 +559,67 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (!mPowerKeyHandled) { mHandler.removeCallbacks(mPowerLongPress); return !canceled; - } else { - mPowerKeyHandled = true; - return false; + } + return false; + } + + private void cancelPendingPowerKeyAction() { + if (!mPowerKeyHandled) { + mHandler.removeCallbacks(mPowerLongPress); + } + mPendingPowerKeyUpCanceled = true; + } + + private void interceptScreenshotChord() { + if (mVolumeDownKeyTriggered && mPowerKeyTriggered && !mVolumeUpKeyTriggered) { + final long now = SystemClock.uptimeMillis(); + if (now <= mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS + && now <= mPowerKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) { + mVolumeDownKeyConsumedByScreenshotChord = true; + cancelPendingPowerKeyAction(); + + mHandler.postDelayed(mScreenshotChordLongPress, + ViewConfiguration.getGlobalActionKeyTimeout()); + } } } + private void cancelPendingScreenshotChordAction() { + mHandler.removeCallbacks(mScreenshotChordLongPress); + } + private final Runnable mPowerLongPress = new Runnable() { public void run() { - if (!mPowerKeyHandled) { - // The context isn't read - if (mLongPressOnPowerBehavior < 0) { - mLongPressOnPowerBehavior = mContext.getResources().getInteger( - com.android.internal.R.integer.config_longPressOnPowerBehavior); - } - switch (mLongPressOnPowerBehavior) { - case LONG_PRESS_POWER_NOTHING: - break; - case LONG_PRESS_POWER_GLOBAL_ACTIONS: - mPowerKeyHandled = true; - performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - showGlobalActionsDialog(); - break; - case LONG_PRESS_POWER_SHUT_OFF: - mPowerKeyHandled = true; - performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); - sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); - ShutdownThread.shutdown(mContext, true); - break; - } + // The context isn't read + if (mLongPressOnPowerBehavior < 0) { + mLongPressOnPowerBehavior = mContext.getResources().getInteger( + com.android.internal.R.integer.config_longPressOnPowerBehavior); + } + switch (mLongPressOnPowerBehavior) { + case LONG_PRESS_POWER_NOTHING: + break; + case LONG_PRESS_POWER_GLOBAL_ACTIONS: + mPowerKeyHandled = true; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + showGlobalActionsDialog(); + break; + case LONG_PRESS_POWER_SHUT_OFF: + mPowerKeyHandled = true; + performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); + ShutdownThread.shutdown(mContext, true); + break; } } }; + private final Runnable mScreenshotChordLongPress = new Runnable() { + public void run() { + takeScreenshot(); + } + }; + void showGlobalActionsDialog() { if (mGlobalActions == null) { mGlobalActions = new GlobalActions(mContext); @@ -1381,11 +1415,12 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override - public boolean interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { + public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags) { final boolean keyguardOn = keyguardOn(); final int keyCode = event.getKeyCode(); final int repeatCount = event.getRepeatCount(); final int metaState = event.getMetaState(); + final int flags = event.getFlags(); final boolean down = event.getAction() == KeyEvent.ACTION_DOWN; final boolean canceled = event.isCanceled(); @@ -1394,6 +1429,26 @@ public class PhoneWindowManager implements WindowManagerPolicy { + repeatCount + " keyguardOn=" + keyguardOn + " mHomePressed=" + mHomePressed); } + // If we think we might have a volume down & power key chord on the way + // but we're not sure, then tell the dispatcher to wait a little while and + // try again later before dispatching. + if ((flags & KeyEvent.FLAG_FALLBACK) == 0) { + if (mVolumeDownKeyTriggered && !mPowerKeyTriggered) { + final long now = SystemClock.uptimeMillis(); + final long timeoutTime = mVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS; + if (now < timeoutTime) { + return timeoutTime - now; + } + } + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN + && mVolumeDownKeyConsumedByScreenshotChord) { + if (!down) { + mVolumeDownKeyConsumedByScreenshotChord = false; + } + return -1; + } + } + // First we always handle the home key here, so applications // can never break it, although if keyguard is on, we do let // it handle it, because that gives us the correct 5 second @@ -1425,7 +1480,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { Log.i(TAG, "Ignoring HOME; event canceled."); } - return true; + return -1; } // If a system window has focus, then it doesn't make sense @@ -1436,13 +1491,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (type == WindowManager.LayoutParams.TYPE_KEYGUARD || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) { // the "app" is keyguard, so give it the key - return false; + return 0; } final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length; for (int i=0; i<typeCount; i++) { if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) { // don't do anything, but also don't pass it to the app - return true; + return -1; } } } @@ -1456,7 +1511,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } } - return true; + return -1; } else if (keyCode == KeyEvent.KEYCODE_MENU) { // Hijack modified menu keys for debugging features final int chordBug = KeyEvent.META_SHIFT_ON; @@ -1465,7 +1520,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mEnableShiftMenuBugReports && (metaState & chordBug) == chordBug) { Intent intent = new Intent(Intent.ACTION_BUG_REPORT); mContext.sendOrderedBroadcast(intent, null); - return true; + return -1; } else if (SHOW_PROCESSES_ON_ALT_MENU && (metaState & KeyEvent.META_ALT_ON) == KeyEvent.META_ALT_ON) { Intent service = new Intent(); @@ -1480,7 +1535,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } Settings.System.putInt( res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1); - return true; + return -1; } } } else if (keyCode == KeyEvent.KEYCODE_SEARCH) { @@ -1493,15 +1548,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { mShortcutKeyPressed = -1; if (mConsumeShortcutKeyUp) { mConsumeShortcutKeyUp = false; - return true; + return -1; } } - return false; + return 0; } else if (keyCode == KeyEvent.KEYCODE_APP_SWITCH) { if (down && repeatCount == 0) { showOrHideRecentAppsDialog(0, true /*dismissIfShown*/); } - return true; + return -1; } // Shortcuts are invoked through Search+key, so intercept those here @@ -1531,11 +1586,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { + "+" + KeyEvent.keyCodeToString(keyCode)); } } - return true; + return -1; } } - return false; + return 0; } /** {@inheritDoc} */ @@ -1606,7 +1661,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { flags, event.getSource(), null); int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags, true); if ((actions & ACTION_PASS_TO_USER) != 0) { - if (!interceptKeyBeforeDispatching(win, fallbackEvent, policyFlags)) { + long delayMillis = interceptKeyBeforeDispatching( + win, fallbackEvent, policyFlags); + if (delayMillis == 0) { if (DEBUG_FALLBACK) { Slog.d(TAG, "Performing fallback."); } @@ -2472,76 +2529,65 @@ public class PhoneWindowManager implements WindowManagerPolicy { final Object mScreenshotLock = new Object(); ServiceConnection mScreenshotConnection = null; - Runnable mScreenshotTimeout = null; - void finishScreenshotLSS(ServiceConnection conn) { - if (mScreenshotConnection == conn) { - mContext.unbindService(conn); - mScreenshotConnection = null; - if (mScreenshotTimeout != null) { - mHandler.removeCallbacks(mScreenshotTimeout); - mScreenshotTimeout = null; + final Runnable mScreenshotTimeout = new Runnable() { + @Override public void run() { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + } } } - } + }; + // Assume this is called from the Handler thread. private void takeScreenshot() { - mHandler.post(new Runnable() { - @Override - public void run() { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != null) { - return; - } - ComponentName cn = new ComponentName("com.android.systemui", - "com.android.systemui.screenshot.TakeScreenshotService"); - Intent intent = new Intent(); - intent.setComponent(cn); - ServiceConnection conn = new ServiceConnection() { - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - synchronized (mScreenshotLock) { - if (mScreenshotConnection != this) { - return; - } - Messenger messenger = new Messenger(service); - Message msg = Message.obtain(null, 1); - final ServiceConnection myConn = this; - Handler h = new Handler(mHandler.getLooper()) { - @Override - public void handleMessage(Message msg) { - synchronized (mScreenshotLock) { - finishScreenshotLSS(myConn); - } - } - }; - msg.replyTo = new Messenger(h); - try { - messenger.send(msg); - } catch (RemoteException e) { - } - } + synchronized (mScreenshotLock) { + if (mScreenshotConnection != null) { + return; + } + ComponentName cn = new ComponentName("com.android.systemui", + "com.android.systemui.screenshot.TakeScreenshotService"); + Intent intent = new Intent(); + intent.setComponent(cn); + ServiceConnection conn = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName name, IBinder service) { + synchronized (mScreenshotLock) { + if (mScreenshotConnection != this) { + return; } - @Override - public void onServiceDisconnected(ComponentName name) {} - }; - if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) { - mScreenshotConnection = conn; - mScreenshotTimeout = new Runnable() { - @Override public void run() { + Messenger messenger = new Messenger(service); + Message msg = Message.obtain(null, 1); + final ServiceConnection myConn = this; + Handler h = new Handler(mHandler.getLooper()) { + @Override + public void handleMessage(Message msg) { synchronized (mScreenshotLock) { - if (mScreenshotConnection != null) { - finishScreenshotLSS(mScreenshotConnection); + if (mScreenshotConnection == myConn) { + mContext.unbindService(mScreenshotConnection); + mScreenshotConnection = null; + mHandler.removeCallbacks(mScreenshotTimeout); } } } - }; - mHandler.postDelayed(mScreenshotTimeout, 10000); + msg.replyTo = new Messenger(h); + try { + messenger.send(msg); + } catch (RemoteException e) { + } } } + @Override + public void onServiceDisconnected(ComponentName name) {} + }; + if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) { + mScreenshotConnection = conn; + mHandler.postDelayed(mScreenshotTimeout, 10000); } - }); + } } /** {@inheritDoc} */ @@ -2609,28 +2655,35 @@ public class PhoneWindowManager implements WindowManagerPolicy { // Handle special keys. switch (keyCode) { case KeyEvent.KEYCODE_VOLUME_DOWN: - if (down) { - if (isScreenOn) { - // If the power key down was already triggered, take the screenshot - if (mPowerDownTriggered) { - // Dismiss the power-key longpress - mHandler.removeCallbacks(mPowerLongPress); - mPowerKeyHandled = true; - - // Take the screenshot - takeScreenshot(); - - // Prevent the event from being passed through to the current activity - result &= ~ACTION_PASS_TO_USER; - break; + case KeyEvent.KEYCODE_VOLUME_UP: + case KeyEvent.KEYCODE_VOLUME_MUTE: { + if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { + if (down) { + if (isScreenOn && !mVolumeDownKeyTriggered + && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + mVolumeDownKeyTriggered = true; + mVolumeDownKeyTime = event.getDownTime(); + mVolumeDownKeyConsumedByScreenshotChord = false; + cancelPendingPowerKeyAction(); + interceptScreenshotChord(); + } + } else { + mVolumeDownKeyTriggered = false; + cancelPendingScreenshotChordAction(); + } + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { + if (down) { + if (isScreenOn && !mVolumeUpKeyTriggered + && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + mVolumeUpKeyTriggered = true; + cancelPendingPowerKeyAction(); + cancelPendingScreenshotChordAction(); } - mVolumeDownTriggered = true; + } else { + mVolumeUpKeyTriggered = false; + cancelPendingScreenshotChordAction(); } - } else { - mVolumeDownTriggered = false; } - case KeyEvent.KEYCODE_VOLUME_UP: - case KeyEvent.KEYCODE_VOLUME_MUTE: { if (down) { ITelephony telephonyService = getTelephonyService(); if (telephonyService != null) { @@ -2709,17 +2762,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { case KeyEvent.KEYCODE_POWER: { result &= ~ACTION_PASS_TO_USER; if (down) { - if (isScreenOn) { - // If the volume down key has been triggered, then just take the screenshot - if (mVolumeDownTriggered) { - // Take the screenshot - takeScreenshot(); - mPowerKeyHandled = true; - - // Prevent the event from being passed through to the current activity - break; - } - mPowerDownTriggered = true; + if (isScreenOn && !mPowerKeyTriggered + && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) { + mPowerKeyTriggered = true; + mPowerKeyTime = event.getDownTime(); + interceptScreenshotChord(); } ITelephony telephonyService = getTelephonyService(); @@ -2741,12 +2788,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { Log.w(TAG, "ITelephony threw RemoteException", ex); } } - interceptPowerKeyDown(!isScreenOn || hungUp); + interceptPowerKeyDown(!isScreenOn || hungUp + || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered); } else { - mPowerDownTriggered = false; - if (interceptPowerKeyUp(canceled)) { + mPowerKeyTriggered = false; + cancelPendingScreenshotChordAction(); + if (interceptPowerKeyUp(canceled || mPendingPowerKeyUpCanceled)) { result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP; } + mPendingPowerKeyUpCanceled = false; } break; } diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index 1eb5f0e..04b4855 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -804,6 +804,18 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, logOutboundKeyDetailsLocked("dispatchKey - ", entry); } + // Handle case where the policy asked us to try again later last time. + if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { + if (currentTime < entry->interceptKeyWakeupTime) { + if (entry->interceptKeyWakeupTime < *nextWakeupTime) { + *nextWakeupTime = entry->interceptKeyWakeupTime; + } + return false; // wait until next wakeup + } + entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; + entry->interceptKeyWakeupTime = 0; + } + // Give the policy a chance to intercept the key. if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { @@ -3827,14 +3839,19 @@ void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( mLock.unlock(); - bool consumed = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, + nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, &event, entry->policyFlags); mLock.lock(); - entry->interceptKeyResult = consumed - ? KeyEntry::INTERCEPT_KEY_RESULT_SKIP - : KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; + if (delay < 0) { + entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; + } else if (!delay) { + entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; + } else { + entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; + entry->interceptKeyWakeupTime = now() + delay; + } entry->release(); } @@ -4156,7 +4173,8 @@ InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, deviceId(deviceId), source(source), action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), metaState(metaState), repeatCount(repeatCount), downTime(downTime), - syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { + syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), + interceptKeyWakeupTime(0) { } InputDispatcher::KeyEntry::~KeyEntry() { @@ -4168,6 +4186,7 @@ void InputDispatcher::KeyEntry::recycle() { dispatchInProgress = false; syntheticRepeat = false; interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; + interceptKeyWakeupTime = 0; } diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h index e78f7bd..8ae5a56 100644 --- a/services/input/InputDispatcher.h +++ b/services/input/InputDispatcher.h @@ -242,7 +242,7 @@ public: virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; /* Allows the policy a chance to intercept a key before dispatching. */ - virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, + virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) = 0; /* Allows the policy a chance to perform default processing for an unhandled key. @@ -481,8 +481,10 @@ private: INTERCEPT_KEY_RESULT_UNKNOWN, INTERCEPT_KEY_RESULT_SKIP, INTERCEPT_KEY_RESULT_CONTINUE, + INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, }; InterceptKeyResult interceptKeyResult; // set based on the interception result + nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER KeyEntry(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, diff --git a/services/input/tests/InputDispatcher_test.cpp b/services/input/tests/InputDispatcher_test.cpp index 8dfb44b..961566f 100644 --- a/services/input/tests/InputDispatcher_test.cpp +++ b/services/input/tests/InputDispatcher_test.cpp @@ -75,9 +75,9 @@ private: virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) { } - virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, + virtual nsecs_t interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { - return false; + return 0; } virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, diff --git a/services/java/com/android/server/wm/InputManager.java b/services/java/com/android/server/wm/InputManager.java index 60333a3..df7e0e1 100644 --- a/services/java/com/android/server/wm/InputManager.java +++ b/services/java/com/android/server/wm/InputManager.java @@ -575,7 +575,7 @@ public class InputManager implements Watchdog.Monitor { } @SuppressWarnings("unused") - public boolean interceptKeyBeforeDispatching(InputWindowHandle focus, + public long interceptKeyBeforeDispatching(InputWindowHandle focus, KeyEvent event, int policyFlags) { return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching( focus, event, policyFlags); diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index 9a559e0..fb74d27 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -288,7 +288,7 @@ final class InputMonitor { /* Provides an opportunity for the window manager policy to process a key before * ordinary dispatch. */ - public boolean interceptKeyBeforeDispatching( + public long interceptKeyBeforeDispatching( InputWindowHandle focus, KeyEvent event, int policyFlags) { WindowState windowState = focus != null ? (WindowState) focus.windowState : null; return mService.mPolicy.interceptKeyBeforeDispatching(windowState, event, policyFlags); diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index f976301..7e9fba8 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -149,6 +149,12 @@ static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t styl } } +enum { + WM_ACTION_PASS_TO_USER = 1, + WM_ACTION_POKE_USER_ACTIVITY = 2, + WM_ACTION_GO_TO_SLEEP = 4, +}; + // --- NativeInputManager --- @@ -199,7 +205,8 @@ public: virtual bool isKeyRepeatEnabled(); virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags); virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags); - virtual bool interceptKeyBeforeDispatching(const sp<InputWindowHandle>& inputWindowHandle, + virtual nsecs_t interceptKeyBeforeDispatching( + const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags); virtual bool dispatchUnhandledKey(const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent); @@ -819,12 +826,6 @@ void NativeInputManager::interceptMotionBeforeQueueing(nsecs_t when, uint32_t& p void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, uint32_t& policyFlags) { - enum { - WM_ACTION_PASS_TO_USER = 1, - WM_ACTION_POKE_USER_ACTIVITY = 2, - WM_ACTION_GO_TO_SLEEP = 4, - }; - if (wmActions & WM_ACTION_GO_TO_SLEEP) { #if DEBUG_INPUT_DISPATCHER_POLICY LOGD("handleInterceptActions: Going to sleep."); @@ -848,14 +849,14 @@ void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when, } } -bool NativeInputManager::interceptKeyBeforeDispatching( +nsecs_t NativeInputManager::interceptKeyBeforeDispatching( const sp<InputWindowHandle>& inputWindowHandle, const KeyEvent* keyEvent, uint32_t policyFlags) { // Policy: // - Ignore untrusted events and pass them along. // - Filter normal events and trusted injected events through the window manager policy to // handle the HOME key and the like. - bool result = false; + nsecs_t result = 0; if (policyFlags & POLICY_FLAG_TRUSTED) { JNIEnv* env = jniEnv(); @@ -863,13 +864,19 @@ bool NativeInputManager::interceptKeyBeforeDispatching( jobject inputWindowHandleObj = getInputWindowHandleObjLocalRef(env, inputWindowHandle); jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent); if (keyEventObj) { - jboolean consumed = env->CallBooleanMethod(mCallbacksObj, + jlong delayMillis = env->CallLongMethod(mCallbacksObj, gCallbacksClassInfo.interceptKeyBeforeDispatching, inputWindowHandleObj, keyEventObj, policyFlags); bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); android_view_KeyEvent_recycle(env, keyEventObj); env->DeleteLocalRef(keyEventObj); - result = consumed && !error; + if (!error) { + if (delayMillis < 0) { + result = -1; + } else if (delayMillis > 0) { + result = milliseconds_to_nanoseconds(delayMillis); + } + } } else { LOGE("Failed to obtain key event object for interceptKeyBeforeDispatching."); } @@ -1433,7 +1440,7 @@ int register_android_server_InputManager(JNIEnv* env) { GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, clazz, "interceptKeyBeforeDispatching", - "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)Z"); + "(Lcom/android/server/wm/InputWindowHandle;Landroid/view/KeyEvent;I)J"); GET_METHOD_ID(gCallbacksClassInfo.dispatchUnhandledKey, clazz, "dispatchUnhandledKey", |