summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/provider/Settings.java6
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java121
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) {