Merge "DO NOT MERGE. Improve screenshot chord debouncing. Bug: 5011907" into ics-mr0
This commit is contained in:
@ -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
|
||||
|
@ -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,37 +559,64 @@ 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();
|
||||
}
|
||||
};
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void onServiceDisconnected(ComponentName name) {}
|
||||
};
|
||||
if (mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE)) {
|
||||
mScreenshotConnection = conn;
|
||||
mScreenshotTimeout = new Runnable() {
|
||||
@Override public void run() {
|
||||
synchronized (mScreenshotLock) {
|
||||
if (mScreenshotConnection != null) {
|
||||
finishScreenshotLSS(mScreenshotConnection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
mHandler.postDelayed(mScreenshotTimeout, 10000);
|
||||
}
|
||||
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() {
|
||||
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) {
|
||||
if (mScreenshotConnection == myConn) {
|
||||
mContext.unbindService(mScreenshotConnection);
|
||||
mScreenshotConnection = null;
|
||||
mHandler.removeCallbacks(mScreenshotTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
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;
|
||||
}
|
||||
mVolumeDownTriggered = true;
|
||||
}
|
||||
} else {
|
||||
mVolumeDownTriggered = false;
|
||||
}
|
||||
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();
|
||||
}
|
||||
} else {
|
||||
mVolumeUpKeyTriggered = false;
|
||||
cancelPendingScreenshotChordAction();
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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",
|
||||
|
Reference in New Issue
Block a user