summaryrefslogtreecommitdiffstats
path: root/policy
diff options
context:
space:
mode:
authorJeff Brown <jeffbrown@google.com>2010-10-29 21:50:21 -0700
committerJeff Brown <jeffbrown@google.com>2010-11-01 15:00:25 -0700
commit4d396052deb54399cbadbeb8abd873df6f3af342 (patch)
tree632cf9922df2abe3b23738792a100a9297517db0 /policy
parent487d9586635e6b209f9a5ed4063f005590d10e85 (diff)
downloadframeworks_base-4d396052deb54399cbadbeb8abd873df6f3af342.zip
frameworks_base-4d396052deb54399cbadbeb8abd873df6f3af342.tar.gz
frameworks_base-4d396052deb54399cbadbeb8abd873df6f3af342.tar.bz2
Fix policy issues when screen is off.
Rewrote interceptKeyBeforeQueueing to make the handling more systematic. Behavior should be identical except: - We never pass keys to applications when the screen is off and the keyguard is not showing (the proximity sensor turned off the screen). Previously we passed all non-wake keys through in this case which caused a bug on Crespo where the screen would come back on if a soft key was held at the time of power off because the resulting key up event would sneak in just before the keyguard was shown. It would then be passed through to the dispatcher which would poke user activity and wake up the screen. - We propagate the key flags when broadcasting media keys which ensures that recipients can tell when the key is canceled. - We ignore endcall or power if canceled (shouldn't happen anyways). Changed the input dispatcher to not poke user activity for canceled events since they are synthetic and should not wake the device. Changed the lock screen so that it does not poke the wake lock when the grab handle is released. This fixes a bug where the screen would come back on immediately if the power went off while the user was holding one of the grab handles because the sliding tab would receive an up event after screen turned off and release the grab handles. Fixed a couple of issues where media keys were being handled inconsistently or not at all, particularly in the case of the new PAUSE, PLAY and RECORD keys. Bug: 3144874 Change-Id: Ie630f5fb6f128cfdf94845f9428067045f42892c
Diffstat (limited to 'policy')
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewBase.java29
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java1
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java12
-rw-r--r--policy/src/com/android/internal/policy/impl/PhoneWindow.java5
-rwxr-xr-xpolicy/src/com/android/internal/policy/impl/PhoneWindowManager.java497
5 files changed, 276 insertions, 268 deletions
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
index 91dc2b2..0f1aa4e 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewBase.java
@@ -145,7 +145,7 @@ public abstract class KeyguardViewBase extends FrameLayout {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAYPAUSE toggle when phone is ringing or
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or
* in-call to avoid music playback */
if (mTelephonyManager == null) {
mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -155,11 +155,13 @@ public abstract class KeyguardViewBase extends FrameLayout {
mTelephonyManager.getCallState() != TelephonyManager.CALL_STATE_IDLE) {
return true; // suppress key event
}
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -191,12 +193,15 @@ public abstract class KeyguardViewBase extends FrameLayout {
} else if (event.getAction() == KeyEvent.ACTION_UP) {
switch (keyCode) {
case KeyEvent.KEYCODE_MUTE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_MEDIA_STOP:
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
index c034ec9..c870503 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewMediator.java
@@ -795,6 +795,7 @@ public class KeyguardViewMediator implements KeyguardViewCallback,
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
case KeyEvent.KEYCODE_CAMERA:
return false;
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 1383354..4644a7c 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -209,7 +209,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
mSlidingTab.setRightHintText(mSilentMode ? R.string.lockscreen_sound_on_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();
+ }
}
}
@@ -231,10 +236,11 @@ class LockScreen extends LinearLayout implements KeyguardScreen,
/** {@inheritDoc} */
public void onGrabbedStateChange(View v, int grabbedState) {
+ // 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 == WaveView.OnTriggerListener.CENTER_HANDLE) {
mCallback.pokeWakelock(STAY_ON_WHILE_GRABBED_TIMEOUT);
- } else {
- mCallback.pokeWakelock();
}
}
}
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 11e1024..e944f9d 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -1252,7 +1252,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- /* Suppress PLAYPAUSE toggle when phone is ringing or in-call
+ /* Suppress PLAY/PAUSE toggle when phone is ringing or in-call
* to avoid music playback */
if (mTelephonyManager == null) {
mTelephonyManager = (TelephonyManager) getContext().getSystemService(
@@ -1268,6 +1268,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
@@ -1448,6 +1449,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MUTE:
case KeyEvent.KEYCODE_MEDIA_PLAY:
case KeyEvent.KEYCODE_MEDIA_PAUSE:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
@@ -1455,6 +1457,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
case KeyEvent.KEYCODE_MEDIA_NEXT:
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: {
Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 7f49da9..e950ae5 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -54,6 +54,7 @@ import com.android.internal.telephony.ITelephony;
import com.android.internal.view.BaseInputHandler;
import com.android.internal.widget.PointerLocationView;
+import android.telephony.TelephonyManager;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
@@ -63,6 +64,7 @@ import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.IWindowManager;
import android.view.InputChannel;
+import android.view.InputDevice;
import android.view.InputQueue;
import android.view.InputHandler;
import android.view.KeyEvent;
@@ -217,7 +219,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
WindowState mKeyguard = null;
KeyguardViewMediator mKeyguardMediator;
GlobalActions mGlobalActions;
- boolean mShouldTurnOffOnKeyUp;
+ volatile boolean mPowerKeyHandled;
RecentApplicationsDialog mRecentAppsDialog;
Handler mHandler;
@@ -477,28 +479,47 @@ 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() {
- // 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:
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- showGlobalActionsDialog();
- break;
- case LONG_PRESS_POWER_SHUT_OFF:
- mShouldTurnOffOnKeyUp = false;
- performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
- sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
- ShutdownThread.shutdown(mContext, true);
- break;
+ 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;
+ }
}
}
};
@@ -1111,12 +1132,22 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.anim.lock_screen_behind_enter);
}
- static ITelephony getPhoneInterface() {
- return ITelephony.Stub.asInterface(ServiceManager.checkService(Context.TELEPHONY_SERVICE));
+ static ITelephony getTelephonyService() {
+ 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() {
- return IAudioService.Stub.asInterface(ServiceManager.checkService(Context.AUDIO_SERVICE));
+ static IAudioService getAudioService() {
+ 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() {
@@ -1131,7 +1162,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
/** {@inheritDoc} */
@Override
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 down = (action == KeyEvent.ACTION_DOWN);
final boolean canceled = ((flags & KeyEvent.FLAG_CANCELED) != 0);
@@ -1164,11 +1195,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// and his ONLY options are to answer or reject the call.)
boolean incomingRinging = false;
try {
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- incomingRinging = phoneServ.isRinging();
- } else {
- Log.w(TAG, "Unable to find ITelephony interface");
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ incomingRinging = telephonyService.isRinging();
}
} catch (RemoteException ex) {
Log.w(TAG, "RemoteException from getPhoneInterface()", ex);
@@ -1824,23 +1853,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.
*/
boolean isMusicActive() {
@@ -1857,9 +1869,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
* @param keycode
*/
void handleVolumeKey(int stream, int keycode) {
- final IAudioService audio = getAudioInterface();
- if (audio == null) {
- Log.w(TAG, "handleVolumeKey: couldn't get IAudioService reference");
+ IAudioService audioService = getAudioService();
+ if (audioService == null) {
return;
}
try {
@@ -1867,7 +1878,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// during the call, but we do it as a precaution for the rare possibility
// that the music stops right before we call this
mBroadcastWakeLock.acquire();
- audio.adjustStreamVolume(stream,
+ audioService.adjustStreamVolume(stream,
keycode == KeyEvent.KEYCODE_VOLUME_UP
? AudioManager.ADJUST_RAISE
: AudioManager.ADJUST_LOWER,
@@ -1878,41 +1889,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mBroadcastWakeLock.release();
}
}
-
- static boolean isMediaKey(int code) {
- if (code == KeyEvent.KEYCODE_HEADSETHOOK ||
- code == KeyEvent.KEYCODE_MEDIA_PLAY ||
- code == KeyEvent.KEYCODE_MEDIA_PAUSE ||
- 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} */
@Override
- public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
- int policyFlags, boolean isScreenOn) {
- int result = ACTION_PASS_TO_USER;
+ public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
+ int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
+ 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;
- if (isInjected) {
- isScreenOn = true;
- }
// 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.
@@ -1927,202 +1912,210 @@ public class PhoneWindowManager implements WindowManagerPolicy {
+ " screenIsOn=" + isScreenOn + " keyguardActive=" + keyguardActive);
}
- if (keyguardActive) {
- if (isScreenOn) {
- // 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 (down && (policyFlags & WindowManagerPolicy.FLAG_VIRTUAL) != 0) {
+ performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);
+ }
- if (isWakeKey && down) {
-
- // tell the mediator about a wake key, it may decide to
- // turn on the screen depending on whether the key is
- // appropriate.
- if (!mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode)
- && (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
- || keyCode == KeyEvent.KEYCODE_VOLUME_UP)) {
- // when keyguard is showing and screen off, we need
- // to handle the volume key for calls and music here
- if (isInCall()) {
- handleVolumeKey(AudioManager.STREAM_VOICE_CALL, keyCode);
- } else if (isMusicActive()) {
- handleVolumeKey(AudioManager.STREAM_MUSIC, keyCode);
+ // 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;
+
+ final boolean isWakeKey = (policyFlags
+ & (WindowManagerPolicy.FLAG_WAKE | WindowManagerPolicy.FLAG_WAKE_DROPPED)) != 0;
+ if (down && isWakeKey) {
+ if (keyguardActive) {
+ // If the keyguard is showing, let it decide what to do with the wake key.
+ mKeyguardMediator.onWakeKeyWhenKeyguardShowingTq(keyCode);
+ } else {
+ // Otherwise, wake the device ourselves.
+ result |= ACTION_POKE_USER_ACTIVITY;
+ }
+ }
+ }
+
+ // Handle special keys.
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_VOLUME_DOWN:
+ case KeyEvent.KEYCODE_VOLUME_UP: {
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ try {
+ if (telephonyService.isRinging()) {
+ // 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.
+ Log.i(TAG, "interceptKeyBeforeQueueing:"
+ + " VOLUME key-down while ringing: Silence ringer!");
+
+ // Silence the ringer. (It's safe to call this
+ // even if the ringer has already been silenced.)
+ telephonyService.silenceRinger();
+
+ // And *don't* pass this key thru to the current activity
+ // (which is probably the InCallScreen.)
+ result &= ~ACTION_PASS_TO_USER;
+ 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;
}
- } 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;
+
+ 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;
+ }
+ }
+ if ((mEndcallBehavior
+ & Settings.System.END_BUTTON_BEHAVIOR_SLEEP) != 0) {
+ result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
+ }
+ }
+ }
+ break;
}
- }
- if (keyCode == KeyEvent.KEYCODE_ENDCALL
- || keyCode == KeyEvent.KEYCODE_POWER) {
- if (down) {
- boolean handled = false;
- boolean hungUp = false;
- // key repeats are generated by the window manager, and we don't see them
- // here, so unless the driver is doing something it shouldn't be, we know
- // this is the real press event.
- ITelephony phoneServ = getPhoneInterface();
- if (phoneServ != null) {
- try {
- if (keyCode == KeyEvent.KEYCODE_ENDCALL) {
- handled = hungUp = phoneServ.endCall();
- } else if (keyCode == KeyEvent.KEYCODE_POWER) {
- if (phoneServ.isRinging()) {
+ 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.
- phoneServ.silenceRinger();
- handled = true;
- } else if (phoneServ.isOffhook() &&
- ((mIncallPowerBehavior
- & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP)
- != 0)) {
+ 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.
- handled = hungUp = phoneServ.endCall();
+ hungUp = telephonyService.endCall();
}
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
- } catch (RemoteException ex) {
- Log.w(TAG, "ITelephony threw RemoteException" + ex);
}
+ interceptPowerKeyDown(!isScreenOn || hungUp);
} else {
- Log.w(TAG, "!!! Unable to find ITelephony interface !!!");
- }
-
- 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)
- || (gohome && !goHome() && sleeps)) {
- // They must already be on the keyguard or home screen,
- // go to sleep instead unless the event was injected.
- if (!isInjected) {
- Log.d(TAG, "I'm tired mEndcallBehavior=0x"
- + Integer.toHexString(mEndcallBehavior));
- result &= ~ACTION_POKE_USER_ACTIVITY;
- result |= ACTION_GO_TO_SLEEP;
- }
+ if (interceptPowerKeyUp(canceled)) {
+ result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
}
- result &= ~ACTION_PASS_TO_USER;
}
+ break;
}
- } 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;
+
+ case KeyEvent.KEYCODE_MEDIA_PLAY:
+ case KeyEvent.KEYCODE_MEDIA_PAUSE:
+ case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
+ if (down) {
+ ITelephony telephonyService = getTelephonyService();
+ if (telephonyService != null) {
+ try {
+ if (!telephonyService.isIdle()) {
+ // Suppress PLAY/PAUSE toggle when phone is ringing or in-call
+ // to avoid music playback.
+ break;
+ }
+ } catch (RemoteException ex) {
+ Log.w(TAG, "ITelephony threw RemoteException", ex);
}
- } else {
- Log.w(TAG, "CALL button: Unable to find ITelephony interface");
}
- } catch (RemoteException ex) {
- Log.w(TAG, "CALL button: RemoteException from getPhoneInterface()", ex);
}
+ case KeyEvent.KEYCODE_HEADSETHOOK:
+ case KeyEvent.KEYCODE_MUTE:
+ case KeyEvent.KEYCODE_MEDIA_STOP:
+ case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_REWIND:
+ case KeyEvent.KEYCODE_MEDIA_RECORD:
+ 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;
}
- } 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;
+
+ 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);
}
- } 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;
}