diff options
-rw-r--r-- | core/java/android/provider/Settings.java | 6 | ||||
-rw-r--r-- | services/core/java/com/android/server/policy/PhoneWindowManager.java | 121 |
2 files changed, 113 insertions, 14 deletions
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index efa02a17b6c0..09583e31067f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5197,6 +5197,12 @@ public final class Settings { */ /** + * Whether or not volume button music controls should be enabled to seek media tracks + * @hide + */ + public static final String VOLBTN_MUSIC_CONTROLS = "volbtn_music_controls"; + + /** * Keys we no longer back up under the current schema, but want to continue to * process when restoring historical backup datasets. * diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index fdd2b14cbd22..871610360e81 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -510,6 +510,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { private boolean mHandleVolumeKeysInWM; + // Behavior of volume button music controls + boolean mVolBtnMusicControls; + boolean mVolBtnLongPress; + private boolean mPendingKeyguardOccluded; private boolean mKeyguardOccludedChanged; @@ -627,6 +631,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { private static final int MSG_HANDLE_ALL_APPS = 22; private static final int MSG_LAUNCH_ASSIST = 23; private static final int MSG_RINGER_TOGGLE_CHORD = 24; + private static final int MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK = 25; private class PolicyHandler extends Handler { @Override @@ -694,6 +699,13 @@ public class PhoneWindowManager implements WindowManagerPolicy { case MSG_RINGER_TOGGLE_CHORD: handleRingerChordGesture(); break; + case MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK: + KeyEvent event = (KeyEvent) msg.obj; + mVolBtnLongPress = true; + dispatchMediaKeyWithWakeLockToAudioService(event); + dispatchMediaKeyWithWakeLockToAudioService( + KeyEvent.changeAction(event, KeyEvent.ACTION_UP)); + break; } } } @@ -768,6 +780,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.POWER_BUTTON_SUPPRESSION_DELAY_AFTER_GESTURE_WAKE), false, this, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.System.getUriFor( + Settings.System.VOLBTN_MUSIC_CONTROLS), false, this, + UserHandle.USER_ALL); updateSettings(); } @@ -2189,6 +2204,9 @@ public class PhoneWindowManager implements WindowManagerPolicy { Settings.Global.KEY_CHORD_POWER_VOLUME_UP, mContext.getResources().getInteger( com.android.internal.R.integer.config_keyChordPowerVolumeUp)); + mVolBtnMusicControls = Settings.System.getIntForUser(resolver, + Settings.System.VOLBTN_MUSIC_CONTROLS, 0, + UserHandle.USER_CURRENT) == 1; } if (updateRotation) { updateRotation(true); @@ -3467,6 +3485,20 @@ public class PhoneWindowManager implements WindowManagerPolicy { mDefaultDisplayPolicy.setHdmiPlugged(plugged, true /* force */); } + /** + * @return Whether music is being played right now "locally" (e.g. on the device's speakers + * or wired headphones) or "remotely" (e.g. on a device using the Cast protocol and + * controlled by this device, or through remote submix). + */ + private boolean isMusicActive() { + final AudioManager am = mContext.getSystemService(AudioManager.class); + if (am == null) { + Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); + return false; + } + return am.isMusicActive(); + } + // TODO(b/117479243): handle it in InputPolicy /** {@inheritDoc} */ @Override @@ -3667,16 +3699,54 @@ public class PhoneWindowManager implements WindowManagerPolicy { break; } } - if (mUseTvRouting || mHandleVolumeKeysInWM) { + if (mUseTvRouting || mHandleVolumeKeysInWM || !mVolBtnMusicControls) { // Defer special key handlings to // {@link interceptKeyBeforeDispatching()}. result |= ACTION_PASS_TO_USER; } else if ((result & ACTION_PASS_TO_USER) == 0) { - // If we aren't passing to the user and no one else - // handled it send it to the session manager to - // figure out. - MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent( - event, AudioManager.USE_DEFAULT_STREAM_TYPE, true); + boolean mayChangeVolume; + + if (isMusicActive()) { + if (mVolBtnMusicControls && (keyCode != KeyEvent.KEYCODE_VOLUME_MUTE)) { + // Detect long key presses. + if (down) { + mVolBtnLongPress = false; + int newKeyCode = event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP ? + KeyEvent.KEYCODE_MEDIA_NEXT + : KeyEvent.KEYCODE_MEDIA_PREVIOUS; + scheduleLongPressKeyEvent(event, newKeyCode); + // Consume key down events of all presses. + break; + } else { + mHandler.removeMessages(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK); + // Consume key up events of long presses only. + if (mVolBtnLongPress) { + break; + } + // Change volume only on key up events of short presses. + mayChangeVolume = true; + } + } else { + // Long key press detection not applicable, change volume only + // on key down events + mayChangeVolume = down; + } + } else { + result |= ACTION_PASS_TO_USER; + break; + } + if (mayChangeVolume) { + // If we aren't passing to the user and no one else + // handled it send it to the session manager to figure + // out. + + // Rewrite the event to use key-down as sendVolumeKeyEvent will + // only change the volume on key down. + KeyEvent newEvent = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode); + MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent( + newEvent, AudioManager.USE_DEFAULT_STREAM_TYPE, true); + } + break; } break; } @@ -4008,6 +4078,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void scheduleLongPressKeyEvent(KeyEvent origEvent, int keyCode) { + KeyEvent event = new KeyEvent(origEvent.getDownTime(), origEvent.getEventTime(), + origEvent.getAction(), keyCode, 0); + Message msg = mHandler.obtainMessage(MSG_DISPATCH_VOLKEY_WITH_WAKE_LOCK, event); + msg.setAsynchronous(true); + mHandler.sendMessageDelayed(msg, ViewConfiguration.getLongPressTimeout()); + } + /** * When the screen is off we ignore some keys that might otherwise typically * be considered wake keys. We filter them out here. @@ -4094,6 +4172,22 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + IDreamManager dreamManager = getDreamManager(); + boolean isDreaming = false; + try { + if (dreamManager != null && dreamManager.isDreaming()) { + isDreaming = true; + } + } catch (RemoteException e) { + Slog.e(TAG, "RemoteException when checking if dreaming", e); + } + + if (isDreaming && isVolumeKey(keyCode)) { + // We don't want the volume key events to be dispatched when the system is deaming in + // order to process them later + return false; + } + // Send events to keyguard while the screen is on and it's showing. if (isKeyguardShowingAndNotOccluded() && !displayOff) { return true; @@ -4112,14 +4206,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (isDefaultDisplay) { // Send events to a dozing dream even if the screen is off since the dream // is in control of the state of the screen. - IDreamManager dreamManager = getDreamManager(); - - try { - if (dreamManager != null && dreamManager.isDreaming()) { - return true; - } - } catch (RemoteException e) { - Slog.e(TAG, "RemoteException when checking if dreaming", e); + if (isDreaming) { + return true; } } @@ -4128,6 +4216,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { return false; } + private static boolean isVolumeKey(int code) { + return code == KeyEvent.KEYCODE_VOLUME_DOWN + || code == KeyEvent.KEYCODE_VOLUME_UP; + } + // pre-condition: event.getKeyCode() is one of KeyEvent.KEYCODE_VOLUME_UP, // KeyEvent.KEYCODE_VOLUME_DOWN, KeyEvent.KEYCODE_VOLUME_MUTE private void dispatchDirectAudioEvent(KeyEvent event) { |