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,