diff options
13 files changed, 356 insertions, 308 deletions
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 1fd31a3..1a341e1 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -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. diff --git a/core/java/android/widget/MediaController.java b/core/java/android/widget/MediaController.java index 39b1377..be1234d 100644 --- a/core/java/android/widget/MediaController.java +++ b/core/java/android/widget/MediaController.java @@ -413,33 +413,46 @@ public class MediaController extends FrameLayout { @Override public boolean dispatchKeyEvent(KeyEvent event) { int keyCode = event.getKeyCode(); - if (event.getRepeatCount() == 0 && event.isDown() && ( - keyCode == KeyEvent.KEYCODE_HEADSETHOOK || - keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || - keyCode == KeyEvent.KEYCODE_SPACE)) { - doPauseResume(); - show(sDefaultTimeout); - if (mPauseButton != null) { - mPauseButton.requestFocus(); + final boolean uniqueDown = event.getRepeatCount() == 0 + && event.getAction() == KeyEvent.ACTION_DOWN; + if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK + || keyCode == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE + || keyCode == KeyEvent.KEYCODE_SPACE) { + if (uniqueDown) { + doPauseResume(); + show(sDefaultTimeout); + if (mPauseButton != null) { + mPauseButton.requestFocus(); + } + } + return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { + if (uniqueDown && !mPlayer.isPlaying()) { + mPlayer.start(); + updatePausePlay(); + show(sDefaultTimeout); } return true; - } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP) { - if (mPlayer.isPlaying()) { + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP + || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { + if (uniqueDown && mPlayer.isPlaying()) { mPlayer.pause(); updatePausePlay(); + show(sDefaultTimeout); } return true; - } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || - keyCode == KeyEvent.KEYCODE_VOLUME_UP) { + } else if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN + || keyCode == KeyEvent.KEYCODE_VOLUME_UP) { // don't show the controls for volume adjustment return super.dispatchKeyEvent(event); } else if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_MENU) { - hide(); - + if (uniqueDown) { + hide(); + } return true; - } else { - show(sDefaultTimeout); } + + show(sDefaultTimeout); return super.dispatchKeyEvent(event); } diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index 3d9cde4..2be7bca 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -529,10 +529,19 @@ public class VideoView extends SurfaceView implements MediaPlayerControl { mMediaController.hide(); } return true; + } else if (keyCode == KeyEvent.KEYCODE_MEDIA_PLAY) { + if (mMediaPlayer.isPlaying()) { + start(); + mMediaController.hide(); + } + return true; } else if (keyCode == KeyEvent.KEYCODE_MEDIA_STOP - && mMediaPlayer.isPlaying()) { - pause(); - mMediaController.show(); + || keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE) { + if (!mMediaPlayer.isPlaying()) { + pause(); + mMediaController.show(); + } + return true; } else { toggleMediaControlsVisiblity(); } diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp index b936c4d..58d4c56 100644 --- a/libs/ui/InputDispatcher.cpp +++ b/libs/ui/InputDispatcher.cpp @@ -1408,8 +1408,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: @@ -1427,6 +1432,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( 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; } diff --git a/services/java/com/android/server/InputManager.java b/services/java/com/android/server/InputManager.java index cb4071a..e7eb129 100644 --- a/services/java/com/android/server/InputManager.java +++ b/services/java/com/android/server/InputManager.java @@ -404,17 +404,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") diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index c29e4a9..55ebded 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -5706,20 +5706,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. diff --git a/services/jni/com_android_server_InputManager.cpp b/services/jni/com_android_server_InputManager.cpp index 599163b..d4c4ba4 100644 --- a/services/jni/com_android_server_InputManager.cpp +++ b/services/jni/com_android_server_InputManager.cpp @@ -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"); @@ -1358,10 +1358,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"); diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 7a1587b..3c4bb12 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -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 */ |