From 7e48204a49db81d9cb58dd1fb40c247d4f3529c7 Mon Sep 17 00:00:00 2001 From: "Austin T. Conn" Date: Wed, 28 Oct 2020 11:06:30 -0300 Subject: base: Long press volume button to skip tracks [1/2] Bring Forward Volume Rocker Track Change Requires Settings Change (packages/apps/Settings) * rituj : AudioService: Allow volume-key long press even when screen is off * mickaelmendes50 : Adapt to Android 11 * Drop previous changes of AudioService as, in theory, the event should never reach it at all. Change-Id: I70b00e08fe48707110725dd1daa56b1e48d15a03 Fix volume rocker skip track on Ambient Display and Lift to Wake we need to check if dream service is dozing before checking keyguard status Change-Id: Ic3a6c830496188bb6edf27043cd24eb2d553bb82 Fix long press volume buttons skip tracks Without that patch, the volume changes up or down prior to skipping tracks because the sendvolumekeyevent doesn't have the mayChangeVolume condition. Also, that part is useless cause the mUseTvRouting condition is taken care of correctly later. Change-Id: I88757315f135f013e7692861d46b3a07fbfc07d5 --- core/java/android/provider/Settings.java | 6 + .../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 @@ -5196,6 +5196,12 @@ public final class Settings { * the setting value. See an example above. */ + /** + * 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) { -- cgit v1.2.3