am c6f2b3b3: Merge "Fix policy issues when screen is off. (DO NOT MERGE)" into gingerbread

* commit 'c6f2b3b302c06b8b7b81ec7e3a43a7df1813d0e0':
  Fix policy issues when screen is off. (DO NOT MERGE)
This commit is contained in:
Jeff Brown
2010-12-23 12:43:48 -08:00
committed by Android Git Automerger
8 changed files with 266 additions and 267 deletions

View File

@ -544,16 +544,18 @@ public interface WindowManagerPolicy {
* Generally, it's best to keep as little as possible in the queue thread * Generally, it's best to keep as little as possible in the queue thread
* because it's the most fragile. * because it's the most fragile.
* @param whenNanos The event time in uptime nanoseconds. * @param whenNanos The event time in uptime nanoseconds.
* @param action The key event action.
* @param flags The key event flags.
* @param keyCode The key code. * @param keyCode The key code.
* @param down True if the key is down. * @param scanCode The key's scan code.
* @param policyFlags The policy flags associated with the key. * @param policyFlags The policy flags associated with the key.
* @param isScreenOn True if the screen is already on * @param isScreenOn True if the screen is already on
* *
* @return The bitwise or of the {@link #ACTION_PASS_TO_USER}, * @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
* {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags. * {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
*/ */
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags, public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
boolean isScreenOn); int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
/** /**
* Called from the input dispatcher thread before a key is dispatched to a window. * Called from the input dispatcher thread before a key is dispatched to a window.
@ -571,6 +573,7 @@ public interface WindowManagerPolicy {
* @param action The key event action. * @param action The key event action.
* @param flags The key event flags. * @param flags The key event flags.
* @param keyCode The key code. * @param keyCode The key code.
* @param scanCode The key's scan code.
* @param metaState bit mask of meta keys that are held. * @param metaState bit mask of meta keys that are held.
* @param repeatCount Number of times a key down has repeated. * @param repeatCount Number of times a key down has repeated.
* @param policyFlags The policy flags associated with the key. * @param policyFlags The policy flags associated with the key.
@ -578,7 +581,7 @@ public interface WindowManagerPolicy {
* not be further dispatched. * not be further dispatched.
*/ */
public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags, public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
int keyCode, int metaState, int repeatCount, int policyFlags); int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags);
/** /**
* Called when layout of the windows is about to start. * Called when layout of the windows is about to start.

View File

@ -1405,8 +1405,13 @@ String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication*
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
int32_t eventType = POWER_MANAGER_BUTTON_EVENT; int32_t eventType = POWER_MANAGER_BUTTON_EVENT;
if (eventEntry->type == EventEntry::TYPE_MOTION) { switch (eventEntry->type) {
case EventEntry::TYPE_MOTION: {
const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry); const MotionEntry* motionEntry = static_cast<const MotionEntry*>(eventEntry);
if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
return;
}
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
switch (motionEntry->action) { switch (motionEntry->action) {
case AMOTION_EVENT_ACTION_DOWN: case AMOTION_EVENT_ACTION_DOWN:
@ -1424,6 +1429,15 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
break; break;
} }
} }
break;
}
case EventEntry::TYPE_KEY: {
const KeyEntry* keyEntry = static_cast<const KeyEntry*>(eventEntry);
if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {
return;
}
break;
}
} }
CommandEntry* commandEntry = postCommandLocked( CommandEntry* commandEntry = postCommandLocked(

View File

@ -333,7 +333,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
mSelector.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label mSelector.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_label
: R.string.lockscreen_sound_off_label); : R.string.lockscreen_sound_off_label);
} }
mCallback.pokeWakelock(); // Don't poke the wake lock when returning to a state where the handle is
// not grabbed since that can happen when the system (instead of the user)
// cancels the grab.
if (grabbedState != SlidingTab.OnTriggerListener.NO_HANDLE) {
mCallback.pokeWakelock();
}
} }
/** /**

View File

@ -61,6 +61,7 @@ import android.view.Gravity;
import android.view.HapticFeedbackConstants; import android.view.HapticFeedbackConstants;
import android.view.IWindowManager; import android.view.IWindowManager;
import android.view.InputChannel; import android.view.InputChannel;
import android.view.InputDevice;
import android.view.InputQueue; import android.view.InputQueue;
import android.view.InputHandler; import android.view.InputHandler;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -204,7 +205,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mKeyguard = null; WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator; KeyguardViewMediator mKeyguardMediator;
GlobalActions mGlobalActions; GlobalActions mGlobalActions;
boolean mShouldTurnOffOnKeyUp; volatile boolean mPowerKeyHandled;
RecentApplicationsDialog mRecentAppsDialog; RecentApplicationsDialog mRecentAppsDialog;
Handler mHandler; Handler mHandler;
@ -456,12 +457,31 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} }
} }
Runnable mPowerLongPress = new Runnable() { private void interceptPowerKeyDown(boolean handled) {
mPowerKeyHandled = handled;
if (!handled) {
mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());
}
}
private boolean interceptPowerKeyUp(boolean canceled) {
if (!mPowerKeyHandled) {
mHandler.removeCallbacks(mPowerLongPress);
return !canceled;
} else {
mPowerKeyHandled = true;
return false;
}
}
private final Runnable mPowerLongPress = new Runnable() {
public void run() { public void run() {
mShouldTurnOffOnKeyUp = false; if (!mPowerKeyHandled) {
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false); mPowerKeyHandled = true;
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
showGlobalActionsDialog(); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
showGlobalActionsDialog();
}
} }
}; };
@ -1041,12 +1061,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.anim.lock_screen_behind_enter); com.android.internal.R.anim.lock_screen_behind_enter);
} }
static ITelephony getPhoneInterface() { static ITelephony getTelephonyService() {
return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE)); ITelephony telephonyService = ITelephony.Stub.asInterface(
ServiceManager.checkService(Context.TELEPHONY_SERVICE));
if (telephonyService == null) {
Log.w(TAG, "Unable to find ITelephony interface.");
}
return telephonyService;
} }
static IAudioService getAudioInterface() { static IAudioService getAudioService() {
return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE)); IAudioService audioService = IAudioService.Stub.asInterface(
ServiceManager.checkService(Context.AUDIO_SERVICE));
if (audioService == null) {
Log.w(TAG, "Unable to find IAudioService interface.");
}
return audioService;
} }
boolean keyguardOn() { boolean keyguardOn() {
@ -1061,7 +1091,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags, public boolean interceptKeyBeforeDispatching(WindowState win, int action, int flags,
int keyCode, int metaState, int repeatCount, int policyFlags) { int keyCode, int scanCode, int metaState, int repeatCount, int policyFlags) {
final boolean keyguardOn = keyguardOn(); final boolean keyguardOn = keyguardOn();
final boolean down = (action == KeyEvent.ACTION_DOWN); final boolean down = (action == KeyEvent.ACTION_DOWN);
final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0); final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@ -1094,11 +1124,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// and his ONLY options are to answer or reject the call.) // and his ONLY options are to answer or reject the call.)
boolean incomingRinging = false; boolean incomingRinging = false;
try { try {
ITelephony phoneServ = getPhoneInterface(); ITelephony telephonyService = getTelephonyService();
if (phoneServ != null) { if (telephonyService != null) {
incomingRinging = phoneServ.isRinging(); incomingRinging = telephonyService.isRinging();
} else {
Log.w(TAG, "Unable to find ITelephony interface");
} }
} catch (RemoteException ex) { } catch (RemoteException ex) {
Log.w(TAG, "RemoteException from getPhoneInterface()", ex); Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
@ -1666,23 +1694,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} }
} }
/**
* @return Whether a telephone call is in progress right now.
*/
boolean isInCall() {
final ITelephony phone = getPhoneInterface();
if (phone == null) {
Log.w(TAG, "couldn't get ITelephony reference");
return false;
}
try {
return phone.isOffhook();
} catch (RemoteException e) {
Log.w(TAG, "ITelephony.isOffhhook threw RemoteException " + e);
return false;
}
}
/** /**
* @return Whether music is being played right now. * @return Whether music is being played right now.
*/ */
@ -1700,9 +1711,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param keycode * @param keycode
*/ */
void handleVolumeKey(int stream, int keycode) { void handleVolumeKey(int stream, int keycode) {
final IAudioService audio = getAudioInterface(); IAudioService audioService = getAudioService();
if (audio == null) { if (audioService == null) {
Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
return; return;
} }
try { try {
@ -1710,7 +1720,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// during the call, but we do it as a precaution for the rare possibility // during the call, but we do it as a precaution for the rare possibility
// that the music stops right before we call this // that the music stops right before we call this
mBroadcastWakeLock.acquire(); mBroadcastWakeLock.acquire();
audio.adjustStreamVolume(stream, audioService.adjustStreamVolume(stream,
keycode == KeyEvent.KEYCODE_VOLUME_UP keycode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE ? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER, : AudioManager.ADJUST_LOWER,
@ -1721,39 +1731,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBroadcastWakeLock.release(); mBroadcastWakeLock.release();
} }
} }
static boolean isMediaKey(int code) {
if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
code == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE ||
code == KeyEvent.KEYCODE_MEDIA_STOP ||
code == KeyEvent.KEYCODE_MEDIA_NEXT ||
code == KeyEvent.KEYCODE_MEDIA_PREVIOUS ||
code == KeyEvent.KEYCODE_MEDIA_REWIND ||
code == KeyEvent.KEYCODE_MEDIA_FAST_FORWARD) {
return true;
}
return false;
}
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
int policyFlags, boolean isScreenOn) { int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
int result = ACTION_PASS_TO_USER; final boolean down = action == KeyEvent.ACTION_DOWN;
final boolean canceled = (flags & KeyEvent.FLAG_CANCELED) != 0;
if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
}
final boolean isWakeKey = (policyFlags
& (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
// If the key is injected, pretend that the screen is on and don't let the
// device go to sleep. This feature is mainly used for testing purposes.
final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0; final boolean isInjected = (policyFlags & WindowManagerPolicy.FLAG_INJECTED) != 0;
if (isInjected) {
isScreenOn = true;
}
// If screen is off then we treat the case where the keyguard is open but hidden // If screen is off then we treat the case where the keyguard is open but hidden
// the same as if it were open and in front. // the same as if it were open and in front.
@ -1768,202 +1754,192 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive); + " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
} }
if (keyguardActive) { if (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
if (isScreenOn) { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
// when the screen is on, always give the event to the keyguard }
result |= ACTION_PASS_TO_USER;
} else {
// otherwise, don't pass it to the user
result &= ~ACTION_PASS_TO_USER;
if (isWakeKey && down) { // Basic policy based on screen state and keyguard.
// FIXME: This policy isn't quite correct. We shouldn't care whether the screen
// is on or off, really. We should care about whether the device is in an
// interactive state or is in suspend pretending to be "off".
// The primary screen might be turned off due to proximity sensor or
// because we are presenting media on an auxiliary screen or remotely controlling
// the device some other way (which is why we have an exemption here for injected
// events).
int result;
if (isScreenOn || isInjected) {
// When the screen is on or if the key is injected pass the key to the application.
result = ACTION_PASS_TO_USER;
} else {
// When the screen is off and the key is not injected, determine whether
// to wake the device but don't pass the key to the application.
result = 0;
// tell the mediator about a wake key, it may decide to final boolean isWakeKey = (policyFlags
// turn on the screen depending on whether the key is & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
// appropriate. if (down && isWakeKey) {
if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode) if (keyguardActive) {
&& (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN // If the keyguard is showing, let it decide what to do with the wake key.
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP)) { mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
// when keyguard is showing and screen off, we need } else {
// to handle the volume key for calls and music here // Otherwise, wake the device ourselves.
if (isInCall()) { result |= ACTION_POKE_USER_ACTIVITY;
handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
} else if (isMusicActive()) {
handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
}
}
} }
} }
} else if (!isScreenOn) {
// If we are in-call with screen off and keyguard is not showing,
// then handle the volume key ourselves.
// This is necessary because the phone app will disable the keyguard
// when the proximity sensor is in use.
if (isInCall() &&
(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
|| keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
result &= ~ACTION_PASS_TO_USER;
handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
}
if (isWakeKey) {
// a wake key has a sole purpose of waking the device; don't pass
// it to the user
result |= ACTION_POKE_USER_ACTIVITY;
result &= ~ACTION_PASS_TO_USER;
}
} }
if (keyCode == KeyEvent.KEYCODE_ENDCALL // Handle special keys.
|| keyCode == KeyEvent.KEYCODE_POWER) { switch (keyCode) {
if (down) { case KeyEvent.KEYCODE_VOLUME_DOWN:
boolean handled = false; case KeyEvent.KEYCODE_VOLUME_UP: {
boolean hungUp = false; if (down) {
// key repeats are generated by the window manager, and we don't see them ITelephony telephonyService = getTelephonyService();
// here, so unless the driver is doing something it shouldn't be, we know if (telephonyService != null) {
// this is the real press event. try {
ITelephony phoneServ = getPhoneInterface(); if (telephonyService.isRinging()) {
if (phoneServ != null) { // If an incoming call is ringing, either VOLUME key means
try { // "silence ringer". We handle these keys here, rather than
if (keyCode == KeyEvent.KEYCODE_ENDCALL) { // in the InCallScreen, to make sure we'll respond to them
handled = hungUp = phoneServ.endCall(); // even if the InCallScreen hasn't come to the foreground yet.
} else if (keyCode == KeyEvent.KEYCODE_POWER) { // Look for the DOWN event here, to agree with the "fallback"
if (phoneServ.isRinging()) { // behavior in the InCallScreen.
// Pressing Power while there's a ringing incoming Log.i(TAG, "interceptKeyBeforeQueueing:"
// call should silence the ringer. + " VOLUME key-down while ringing: Silence ringer!");
phoneServ.silenceRinger();
handled = true; // Silence the ringer. (It's safe to call this
} else if (phoneServ.isOffhook() && // even if the ringer has already been silenced.)
((mIncallPowerBehavior telephonyService.silenceRinger();
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
!= 0)) { // And *don't* pass this key thru to the current activity
// Otherwise, if "Power button ends call" is enabled, // (which is probably the InCallScreen.)
// the Power button will hang up any current active call. result &= ~ACTION_PASS_TO_USER;
handled = hungUp = phoneServ.endCall(); break;
}
if (telephonyService.isOffhook()
&& (result & ACTION_PASS_TO_USER) == 0) {
// If we are in call but we decided not to pass the key to
// the application, handle the volume change here.
handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
break;
}
} catch (RemoteException ex) {
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
if (isMusicActive() && (result & ACTION_PASS_TO_USER) == 0) {
// If music is playing but we decided not to pass the key to the
// application, handle the volume change here.
handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
break;
}
}
break;
}
case KeyEvent.KEYCODE_ENDCALL: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
ITelephony telephonyService = getTelephonyService();
boolean hungUp = false;
if (telephonyService != null) {
try {
hungUp = telephonyService.endCall();
} catch (RemoteException ex) {
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
interceptPowerKeyDown(!isScreenOn || hungUp);
} else {
if (interceptPowerKeyUp(canceled)) {
if ((mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0) {
if (goHome()) {
break;
} }
} }
} catch (RemoteException ex) { if ((mEndcallBehavior
Log.w(TAG, "ITelephony threw RemoteException" + ex); & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
}
} }
}
break;
}
case KeyEvent.KEYCODE_POWER: {
result &= ~ACTION_PASS_TO_USER;
if (down) {
ITelephony telephonyService = getTelephonyService();
boolean hungUp = false;
if (telephonyService != null) {
try {
if (telephonyService.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
telephonyService.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telephonyService.isOffhook()) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
hungUp = telephonyService.endCall();
}
} catch (RemoteException ex) {
Log.w(TAG, "ITelephony threw RemoteException", ex);
}
}
interceptPowerKeyDown(!isScreenOn || hungUp);
} else { } else {
Log.w(TAG, "!!! Unable to find ITelephony interface !!!"); if (interceptPowerKeyUp(canceled)) {
} result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
if (!isScreenOn
|| (handled && keyCode != KeyEvent.KEYCODE_POWER)
|| (handled && hungUp && keyCode == KeyEvent.KEYCODE_POWER)) {
mShouldTurnOffOnKeyUp = false;
} else {
// Only try to turn off the screen if we didn't already hang up.
mShouldTurnOffOnKeyUp = true;
mHandler.postDelayed(mPowerLongPress,
ViewConfiguration.getGlobalActionKeyTimeout());
result &= ~ACTION_PASS_TO_USER;
}
} else {
mHandler.removeCallbacks(mPowerLongPress);
if (mShouldTurnOffOnKeyUp) {
mShouldTurnOffOnKeyUp = false;
boolean gohome, sleeps;
if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
gohome = (mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_HOME) != 0;
sleeps = (mEndcallBehavior
& Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0;
} else {
gohome = false;
sleeps = true;
} }
if (keyguardActive }
|| (sleeps && !gohome) break;
|| (gohome && !goHome() && sleeps)) { }
// They must already be on the keyguard or home screen,
// go to sleep instead unless the event was injected. case KeyEvent.KEYCODE_HEADSETHOOK:
if (!isInjected) { case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
Log.d(TAG, "I'm tired mEndcallBehavior=0x" case KeyEvent.KEYCODE_MEDIA_STOP:
+ Integer.toHexString(mEndcallBehavior)); case KeyEvent.KEYCODE_MEDIA_NEXT:
result &= ~ACTION_POKE_USER_ACTIVITY; case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
result |= ACTION_GO_TO_SLEEP; case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
long when = whenNanos / 1000000;
KeyEvent keyEvent = new KeyEvent(when, when, action, keyCode, 0, 0,
0, scanCode, flags, InputDevice.SOURCE_KEYBOARD);
mBroadcastWakeLock.acquire();
mHandler.post(new PassHeadsetKey(keyEvent));
}
break;
}
case KeyEvent.KEYCODE_CALL: {
if (down) {
ITelephony telephonyService = getTelephonyService();
if (telephonyService != null) {
try {
if (telephonyService.isRinging()) {
Log.i(TAG, "interceptKeyBeforeQueueing:"
+ " CALL key-down while ringing: Answer the call!");
telephonyService.answerRingingCall();
// And *don't* pass this key thru to the current activity
// (which is presumably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
}
} catch (RemoteException ex) {
Log.w(TAG, "ITelephony threw RemoteException", ex);
} }
} }
result &= ~ACTION_PASS_TO_USER;
}
}
} else if (isMediaKey(keyCode)) {
// This key needs to be handled even if the screen is off.
// If others need to be handled while it's off, this is a reasonable
// pattern to follow.
if ((result & ACTION_PASS_TO_USER) == 0) {
// Only do this if we would otherwise not pass it to the user. In that
// case, the PhoneWindow class will do the same thing, except it will
// only do it if the showing app doesn't process the key on its own.
long when = whenNanos / 1000000;
KeyEvent keyEvent = new KeyEvent(when, when,
down ? KeyEvent.ACTION_DOWN : KeyEvent.ACTION_UP,
keyCode, 0);
mBroadcastWakeLock.acquire();
mHandler.post(new PassHeadsetKey(keyEvent));
}
} else if (keyCode == KeyEvent.KEYCODE_CALL) {
// If an incoming call is ringing, answer it!
// (We handle this key here, rather than in the InCallScreen, to make
// sure we'll respond to the key even if the InCallScreen hasn't come to
// the foreground yet.)
// We answer the call on the DOWN event, to agree with
// the "fallback" behavior in the InCallScreen.
if (down) {
try {
ITelephony phoneServ = getPhoneInterface();
if (phoneServ != null) {
if (phoneServ.isRinging()) {
Log.i(TAG, "interceptKeyTq:"
+ " CALL key-down while ringing: Answer the call!");
phoneServ.answerRingingCall();
// And *don't* pass this key thru to the current activity
// (which is presumably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
}
} else {
Log.w(TAG, "CALL button: Unable to find ITelephony interface");
}
} catch (RemoteException ex) {
Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
}
}
} else if ((keyCode == KeyEvent.KEYCODE_VOLUME_UP)
|| (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
// If an incoming call is ringing, either VOLUME key means
// "silence ringer". We handle these keys here, rather than
// in the InCallScreen, to make sure we'll respond to them
// even if the InCallScreen hasn't come to the foreground yet.
// Look for the DOWN event here, to agree with the "fallback"
// behavior in the InCallScreen.
if (down) {
try {
ITelephony phoneServ = getPhoneInterface();
if (phoneServ != null) {
if (phoneServ.isRinging()) {
Log.i(TAG, "interceptKeyTq:"
+ " VOLUME key-down while ringing: Silence ringer!");
// Silence the ringer. (It's safe to call this
// even if the ringer has already been silenced.)
phoneServ.silenceRinger();
// And *don't* pass this key thru to the current activity
// (which is probably the InCallScreen.)
result &= ~ACTION_PASS_TO_USER;
}
} else {
Log.w(TAG, "VOLUME button: Unable to find ITelephony interface");
}
} catch (RemoteException ex) {
Log.w(TAG, "VOLUME button: RemoteException from getPhoneInterface()", ex);
} }
break;
} }
} }
return result; return result;
} }

View File

@ -379,17 +379,18 @@ public class InputManager {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
int policyFlags, boolean isScreenOn) { int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing( return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
whenNanos, keyCode, down, policyFlags, isScreenOn); whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
public boolean interceptKeyBeforeDispatching(InputChannel focus, int action, public boolean interceptKeyBeforeDispatching(InputChannel focus, int action,
int flags, int keyCode, int metaState, int repeatCount, int policyFlags) { int flags, int keyCode, int scanCode, int metaState, int repeatCount,
int policyFlags) {
return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus, return mWindowManagerService.mInputMonitor.interceptKeyBeforeDispatching(focus,
action, flags, keyCode, metaState, repeatCount, policyFlags); action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")

View File

@ -5251,20 +5251,20 @@ public class WindowManagerService extends IWindowManager.Stub
/* Provides an opportunity for the window manager policy to intercept early key /* Provides an opportunity for the window manager policy to intercept early key
* processing as soon as the key has been read from the device. */ * processing as soon as the key has been read from the device. */
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
int policyFlags, boolean isScreenOn) { int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
return mPolicy.interceptKeyBeforeQueueing(whenNanos, return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
keyCode, down, policyFlags, isScreenOn); keyCode, scanCode, policyFlags, isScreenOn);
} }
/* Provides an opportunity for the window manager policy to process a key before /* Provides an opportunity for the window manager policy to process a key before
* ordinary dispatch. */ * ordinary dispatch. */
public boolean interceptKeyBeforeDispatching(InputChannel focus, public boolean interceptKeyBeforeDispatching(InputChannel focus,
int action, int flags, int keyCode, int metaState, int repeatCount, int action, int flags, int keyCode, int scanCode, int metaState, int repeatCount,
int policyFlags) { int policyFlags) {
WindowState windowState = getWindowStateForInputChannel(focus); WindowState windowState = getWindowStateForInputChannel(focus);
return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags, return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
keyCode, metaState, repeatCount, policyFlags); keyCode, scanCode, metaState, repeatCount, policyFlags);
} }
/* Called when the current input focus changes. /* Called when the current input focus changes.

View File

@ -857,7 +857,7 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
JNIEnv* env = jniEnv(); JNIEnv* env = jniEnv();
jint wmActions = env->CallIntMethod(mCallbacksObj, jint wmActions = env->CallIntMethod(mCallbacksObj,
gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.interceptKeyBeforeQueueing,
when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn); when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) { if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0; wmActions = 0;
} }
@ -926,7 +926,7 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
jboolean consumed = env->CallBooleanMethod(mCallbacksObj, jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.interceptKeyBeforeDispatching,
inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(), inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
keyEvent->getKeyCode(), keyEvent->getMetaState(), keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
keyEvent->getRepeatCount(), policyFlags); keyEvent->getRepeatCount(), policyFlags);
bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching"); bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
@ -1337,10 +1337,10 @@ int register_android_server_InputManager(JNIEnv* env) {
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J"); "notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz, GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
"interceptKeyBeforeQueueing", "(JIZIZ)I"); "interceptKeyBeforeQueueing", "(JIIIIIZ)I");
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz, GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeDispatching, gCallbacksClassInfo.clazz,
"interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIII)Z"); "interceptKeyBeforeDispatching", "(Landroid/view/InputChannel;IIIIIII)Z");
GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz, GET_METHOD_ID(gCallbacksClassInfo.checkInjectEventsPermission, gCallbacksClassInfo.clazz,
"checkInjectEventsPermission", "(II)Z"); "checkInjectEventsPermission", "(II)Z");

View File

@ -66,7 +66,7 @@ interface ITelephony {
boolean showCallScreenWithDialpad(boolean showDialpad); boolean showCallScreenWithDialpad(boolean showDialpad);
/** /**
* End call or go to the Home screen * End call if there is a call in progress, otherwise does nothing.
* *
* @return whether it hung up * @return whether it hung up
*/ */