summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWinson Chung <winsonc@google.com>2011-10-12 17:00:11 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-10-12 17:00:11 -0700
commita76a87a8efbc1e6d3d6f503d937ab18a91638ecf (patch)
tree7c1a59324d43ee2baf352aa5c319fd3662c02aed
parentf838b7c2b8c4f0f1c48f315f49fea340b2b10d83 (diff)
parentd5bb82d18cbd95bb9e751d8315b9ed0b69595033 (diff)
downloadframeworks_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.java20
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java310
-rw-r--r--services/input/InputDispatcher.cpp29
-rw-r--r--services/input/InputDispatcher.h4
-rw-r--r--services/input/tests/InputDispatcher_test.cpp4
-rw-r--r--services/java/com/android/server/wm/InputManager.java2
-rw-r--r--services/java/com/android/server/wm/InputMonitor.java2
-rw-r--r--services/jni/com_android_server_InputManager.cpp31
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",