From 3c45c29109d23981d8b707c809b3b43ce2e20fc3 Mon Sep 17 00:00:00 2001 From: RoboErik Date: Tue, 8 Jul 2014 16:47:31 -0700 Subject: [PATCH] Pipe volume keys to adjustVolume instead of sendMediaKeyEvent We were calling sendMediaKeyEvent with a KEYCODE_VOLUME key, which was being ignored because it's not a media key. This redirects the volume keys to use the adjustVolume methods instead. It also sends the appropriate flags to make the lock screen consistent with the home screen and the volume keys only affect active playback when the screen is off. bug:15900519 Change-Id: I9f3853a2385869353a58debae6e6ca9933ba06ce --- media/java/android/media/AudioManager.java | 6 +++ .../android/media/session/MediaSession.java | 19 ++++++++ .../session/MediaSessionLegacyHelper.java | 48 +++++++++++++++++++ .../impl/PhoneFallbackEventHandler.java | 8 +--- .../policy/impl/PhoneWindowManager.java | 24 +++------- .../server/media/MediaSessionRecord.java | 25 +--------- .../server/media/MediaSessionService.java | 7 +++ 7 files changed, 91 insertions(+), 46 deletions(-) diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index ffbe2cb8c6cf8..5bcbc3c3898dd 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -345,6 +345,12 @@ public class AudioManager { */ public static final int FLAG_HDMI_SYSTEM_AUDIO_VOLUME = 1 << 8; + /** + * Indicates that this should only be handled if media is actively playing. + * @hide + */ + public static final int FLAG_ACTIVE_MEDIA_ONLY = 1 << 9; + /** * Ringer mode that will be silent and will not vibrate. (This overrides the * vibrate setting.) diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index dbe13ddbe234b..2cbdc96eefe99 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -698,6 +698,25 @@ public final class MediaSession { } } + /** + * Return true if this is considered an active playback state. + * + * @hide + */ + public static boolean isActiveState(int state) { + switch (state) { + case PlaybackState.STATE_FAST_FORWARDING: + case PlaybackState.STATE_REWINDING: + case PlaybackState.STATE_SKIPPING_TO_PREVIOUS: + case PlaybackState.STATE_SKIPPING_TO_NEXT: + case PlaybackState.STATE_BUFFERING: + case PlaybackState.STATE_CONNECTING: + case PlaybackState.STATE_PLAYING: + return true; + } + return false; + } + /** * Represents an ongoing session. This may be passed to apps by the session * owner to allow them to create a {@link MediaController} to communicate with diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java index 0b04485bc67d0..5d1a7e0280fc2 100644 --- a/media/java/android/media/session/MediaSessionLegacyHelper.java +++ b/media/java/android/media/session/MediaSessionLegacyHelper.java @@ -21,6 +21,7 @@ import android.app.PendingIntent.CanceledException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.media.AudioManager; import android.media.MediaMetadata; import android.media.MediaMetadataEditor; import android.media.MediaMetadataRetriever; @@ -157,12 +158,59 @@ public class MediaSessionLegacyHelper { } public void sendMediaButtonEvent(KeyEvent keyEvent, boolean needWakeLock) { + if (keyEvent == null) { + Log.w(TAG, "Tried to send a null key event. Ignoring."); + return; + } mSessionManager.dispatchMediaKeyEvent(keyEvent, needWakeLock); if (DEBUG) { Log.d(TAG, "dispatched media key " + keyEvent); } } + public void sendVolumeKeyEvent(KeyEvent keyEvent, boolean musicOnly) { + if (keyEvent == null) { + Log.w(TAG, "Tried to send a null key event. Ignoring."); + return; + } + boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN; + boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP; + int direction = 0; + switch (keyEvent.getKeyCode()) { + case KeyEvent.KEYCODE_VOLUME_UP: + direction = AudioManager.ADJUST_RAISE; + break; + case KeyEvent.KEYCODE_VOLUME_DOWN: + direction = AudioManager.ADJUST_LOWER; + break; + case KeyEvent.KEYCODE_VOLUME_MUTE: + // TODO + break; + } + if ((down || up) && direction != 0) { + int flags; + // If this is action up we want to send a beep for non-music events + if (up) { + direction = 0; + } + if (musicOnly) { + // This flag is used when the screen is off to only affect + // active media + flags = AudioManager.FLAG_ACTIVE_MEDIA_ONLY; + } else { + // These flags are consistent with the home screen + if (up) { + flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE; + } else { + flags = AudioManager.FLAG_SHOW_UI; + } + } + + mSessionManager.dispatchAdjustVolumeBy(AudioManager.USE_DEFAULT_STREAM_TYPE, + direction, flags); + } + } + public void sendAdjustVolumeBy(int suggestedStream, int delta, int flags) { mSessionManager.dispatchAdjustVolumeBy(suggestedStream, delta, flags); if (DEBUG) { diff --git a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java index 4ad45a8e234e4..f291e89f3154c 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java +++ b/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java @@ -83,7 +83,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { case KeyEvent.KEYCODE_VOLUME_UP: case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { - getAudioManager().handleKeyDown(event, AudioManager.USE_DEFAULT_STREAM_TYPE); + MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); return true; } @@ -198,11 +198,7 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler { case KeyEvent.KEYCODE_VOLUME_DOWN: case KeyEvent.KEYCODE_VOLUME_MUTE: { if (!event.isCanceled()) { - AudioManager audioManager = (AudioManager)mContext.getSystemService( - Context.AUDIO_SERVICE); - if (audioManager != null) { - getAudioManager().handleKeyUp(event, AudioManager.USE_DEFAULT_STREAM_TYPE); - } + MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false); } return true; } diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index c668f5a6eea5d..0b1252ea361e0 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -45,7 +45,11 @@ import android.media.AudioManager; import android.media.IAudioService; import android.media.Ringtone; import android.media.RingtoneManager; +import android.media.session.MediaController; +import android.media.session.MediaSession; import android.media.session.MediaSessionLegacyHelper; +import android.media.session.MediaSessionManager; +import android.media.session.PlaybackState; import android.os.Bundle; import android.os.FactoryTest; import android.os.Handler; @@ -113,6 +117,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; @@ -4006,21 +4011,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { setHdmiPlugged(!mHdmiPlugged); } - /** - * @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). - */ - boolean isMusicActive() { - - final AudioManager am = (AudioManager)mContext.getSystemService(Context.AUDIO_SERVICE); - if (am == null) { - Log.w(TAG, "isMusicActive: couldn't get AudioManager reference"); - return false; - } - return am.isLocalOrRemoteMusicActive(); - } - final Object mScreenshotLock = new Object(); ServiceConnection mScreenshotConnection = null; @@ -4210,7 +4200,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the application, just pass it to the session service. MediaSessionLegacyHelper.getHelper(mContext) - .sendMediaButtonEvent(event, true); + .sendVolumeKeyEvent(event, false); break; } } @@ -4220,7 +4210,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { // handled it send it to the session manager to figure // out. MediaSessionLegacyHelper.getHelper(mContext) - .sendMediaButtonEvent(event, true); + .sendVolumeKeyEvent(event, true); break; } } diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index aeade50b019c8..0fbcd7efcf722 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -67,18 +67,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private static final String TAG = "MediaSessionRecord"; private static final boolean DEBUG = false; - /** - * These are the playback states that count as currently active. - */ - private static final int[] ACTIVE_STATES = { - PlaybackState.STATE_FAST_FORWARDING, - PlaybackState.STATE_REWINDING, - PlaybackState.STATE_SKIPPING_TO_PREVIOUS, - PlaybackState.STATE_SKIPPING_TO_NEXT, - PlaybackState.STATE_BUFFERING, - PlaybackState.STATE_CONNECTING, - PlaybackState.STATE_PLAYING }; - /** * The length of time a session will still be considered active after * pausing in ms. @@ -402,7 +390,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { */ public boolean isPlaybackActive(boolean includeRecentlyActive) { int state = mPlaybackState == null ? 0 : mPlaybackState.getState(); - if (isActiveState(state)) { + if (MediaSession.isActiveState(state)) { return true; } if (includeRecentlyActive && state == mPlaybackState.STATE_PAUSED) { @@ -555,15 +543,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { pw.println(indent + "params=" + (mRequest == null ? null : mRequest.toString())); } - private boolean isActiveState(int state) { - for (int i = 0; i < ACTIVE_STATES.length; i++) { - if (ACTIVE_STATES[i] == state) { - return true; - } - } - return false; - } - private String getShortMetadataString() { int fields = mMetadata == null ? 0 : mMetadata.size(); String title = mMetadata == null ? null : mMetadata @@ -804,7 +783,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { public void setPlaybackState(PlaybackState state) { int oldState = mPlaybackState == null ? 0 : mPlaybackState.getState(); int newState = state == null ? 0 : state.getState(); - if (isActiveState(oldState) && newState == PlaybackState.STATE_PAUSED) { + if (MediaSession.isActiveState(oldState) && newState == PlaybackState.STATE_PAUSED) { mLastActiveTime = SystemClock.elapsedRealtime(); } mPlaybackState = state; diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 5a16e4ddb9bdc..310f3e9981275 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -27,6 +27,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.media.AudioManager; import android.media.IAudioService; import android.media.IRemoteVolumeController; import android.media.routeprovider.RouteRequest; @@ -948,6 +949,12 @@ public class MediaSessionService extends SystemService implements Monitor { } if (session == null) { + if ((flags & AudioManager.FLAG_ACTIVE_MEDIA_ONLY) != 0) { + if (DEBUG) { + Log.d(TAG, "No active session to adjust, skipping media only volume event"); + return; + } + } try { if (delta == 0) { mAudioService.adjustSuggestedStreamVolume(delta, suggestedStream, flags,