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:
@ -544,16 +544,18 @@ public interface WindowManagerPolicy {
|
||||
* Generally, it's best to keep as little as possible in the queue thread
|
||||
* because it's the most fragile.
|
||||
* @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 down True if the key is down.
|
||||
* @param scanCode The key's scan code.
|
||||
* @param policyFlags The policy flags associated with the key.
|
||||
* @param isScreenOn True if the screen is already on
|
||||
*
|
||||
* @return The bitwise or of the {@link #ACTION_PASS_TO_USER},
|
||||
* {@link #ACTION_POKE_USER_ACTIVITY} and {@link #ACTION_GO_TO_SLEEP} flags.
|
||||
*/
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down, int policyFlags,
|
||||
boolean isScreenOn);
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
|
||||
int keyCode, int scanCode, int policyFlags, boolean isScreenOn);
|
||||
|
||||
/**
|
||||
* 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 flags The key event flags.
|
||||
* @param keyCode The key code.
|
||||
* @param scanCode The key's scan code.
|
||||
* @param metaState bit mask of meta keys that are held.
|
||||
* @param repeatCount Number of times a key down has repeated.
|
||||
* @param policyFlags The policy flags associated with the key.
|
||||
@ -578,7 +581,7 @@ public interface WindowManagerPolicy {
|
||||
* not be further dispatched.
|
||||
*/
|
||||
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.
|
||||
|
@ -1405,8 +1405,13 @@ String8 InputDispatcher::getApplicationWindowLabelLocked(const InputApplication*
|
||||
|
||||
void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
|
||||
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);
|
||||
if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) {
|
||||
switch (motionEntry->action) {
|
||||
case AMOTION_EVENT_ACTION_DOWN:
|
||||
@ -1424,6 +1429,15 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
|
||||
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(
|
||||
|
@ -333,7 +333,12 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
|
||||
mSelector.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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,6 +61,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;
|
||||
@ -204,7 +205,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
WindowState mKeyguard = null;
|
||||
KeyguardViewMediator mKeyguardMediator;
|
||||
GlobalActions mGlobalActions;
|
||||
boolean mShouldTurnOffOnKeyUp;
|
||||
volatile boolean mPowerKeyHandled;
|
||||
RecentApplicationsDialog mRecentAppsDialog;
|
||||
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() {
|
||||
mShouldTurnOffOnKeyUp = false;
|
||||
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
|
||||
sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);
|
||||
showGlobalActionsDialog();
|
||||
if (!mPowerKeyHandled) {
|
||||
mPowerKeyHandled = true;
|
||||
performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
|
||||
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);
|
||||
}
|
||||
|
||||
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() {
|
||||
@ -1061,7 +1091,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);
|
||||
@ -1094,11 +1124,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);
|
||||
@ -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.
|
||||
*/
|
||||
@ -1700,9 +1711,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 {
|
||||
@ -1710,7 +1720,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,
|
||||
@ -1721,39 +1731,15 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|
||||
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} */
|
||||
@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.
|
||||
@ -1768,202 +1754,192 @@ 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) {
|
||||
// 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
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
} 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
|
||||
|| 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()) {
|
||||
// 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)) {
|
||||
// Otherwise, if "Power button ends call" is enabled,
|
||||
// the Power button will hang up any current active call.
|
||||
handled = hungUp = phoneServ.endCall();
|
||||
// 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;
|
||||
}
|
||||
|
||||
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) {
|
||||
Log.w(TAG, "ITelephony threw RemoteException" + ex);
|
||||
if ((mEndcallBehavior
|
||||
& 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 {
|
||||
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 (interceptPowerKeyUp(canceled)) {
|
||||
result = (result & ~ACTION_POKE_USER_ACTIVITY) | ACTION_GO_TO_SLEEP;
|
||||
}
|
||||
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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
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_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;
|
||||
}
|
||||
|
||||
|
@ -379,17 +379,18 @@ public class InputManager {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
|
||||
int policyFlags, boolean isScreenOn) {
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
|
||||
int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
|
||||
return mWindowManagerService.mInputMonitor.interceptKeyBeforeQueueing(
|
||||
whenNanos, keyCode, down, policyFlags, isScreenOn);
|
||||
whenNanos, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
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,
|
||||
action, flags, keyCode, metaState, repeatCount, policyFlags);
|
||||
action, flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -5251,20 +5251,20 @@ public class WindowManagerService extends IWindowManager.Stub
|
||||
|
||||
/* Provides an opportunity for the window manager policy to intercept early key
|
||||
* processing as soon as the key has been read from the device. */
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int keyCode, boolean down,
|
||||
int policyFlags, boolean isScreenOn) {
|
||||
return mPolicy.interceptKeyBeforeQueueing(whenNanos,
|
||||
keyCode, down, policyFlags, isScreenOn);
|
||||
public int interceptKeyBeforeQueueing(long whenNanos, int action, int flags,
|
||||
int keyCode, int scanCode, int policyFlags, boolean isScreenOn) {
|
||||
return mPolicy.interceptKeyBeforeQueueing(whenNanos, action, flags,
|
||||
keyCode, scanCode, policyFlags, isScreenOn);
|
||||
}
|
||||
|
||||
/* Provides an opportunity for the window manager policy to process a key before
|
||||
* ordinary dispatch. */
|
||||
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) {
|
||||
WindowState windowState = getWindowStateForInputChannel(focus);
|
||||
return mPolicy.interceptKeyBeforeDispatching(windowState, action, flags,
|
||||
keyCode, metaState, repeatCount, policyFlags);
|
||||
keyCode, scanCode, metaState, repeatCount, policyFlags);
|
||||
}
|
||||
|
||||
/* Called when the current input focus changes.
|
||||
|
@ -857,7 +857,7 @@ void NativeInputManager::interceptKeyBeforeQueueing(nsecs_t when,
|
||||
JNIEnv* env = jniEnv();
|
||||
jint wmActions = env->CallIntMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.interceptKeyBeforeQueueing,
|
||||
when, keyCode, action == AKEY_EVENT_ACTION_DOWN, policyFlags, isScreenOn);
|
||||
when, action, flags, keyCode, scanCode, policyFlags, isScreenOn);
|
||||
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
|
||||
wmActions = 0;
|
||||
}
|
||||
@ -926,7 +926,7 @@ bool NativeInputManager::interceptKeyBeforeDispatching(const sp<InputChannel>& i
|
||||
jboolean consumed = env->CallBooleanMethod(mCallbacksObj,
|
||||
gCallbacksClassInfo.interceptKeyBeforeDispatching,
|
||||
inputChannelObj, keyEvent->getAction(), keyEvent->getFlags(),
|
||||
keyEvent->getKeyCode(), keyEvent->getMetaState(),
|
||||
keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
|
||||
keyEvent->getRepeatCount(), policyFlags);
|
||||
bool error = checkAndClearExceptionFromCallback(env, "interceptKeyBeforeDispatching");
|
||||
|
||||
@ -1337,10 +1337,10 @@ int register_android_server_InputManager(JNIEnv* env) {
|
||||
"notifyANR", "(Ljava/lang/Object;Landroid/view/InputChannel;)J");
|
||||
|
||||
GET_METHOD_ID(gCallbacksClassInfo.interceptKeyBeforeQueueing, gCallbacksClassInfo.clazz,
|
||||
"interceptKeyBeforeQueueing", "(JIZIZ)I");
|
||||
"interceptKeyBeforeQueueing", "(JIIIIIZ)I");
|
||||
|
||||
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,
|
||||
"checkInjectEventsPermission", "(II)Z");
|
||||
|
@ -66,7 +66,7 @@ interface ITelephony {
|
||||
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
|
||||
*/
|
||||
|
Reference in New Issue
Block a user