summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/AudioManager.java27
-rw-r--r--media/java/android/media/AudioManagerInternal.java5
-rw-r--r--media/java/android/media/AudioService.java30
-rw-r--r--media/java/android/media/session/MediaSessionLegacyHelper.java29
-rw-r--r--media/java/android/media/session/MediaSessionManager.java8
-rw-r--r--services/core/java/com/android/server/media/MediaSessionRecord.java42
-rw-r--r--services/core/java/com/android/server/media/MediaSessionService.java26
7 files changed, 136 insertions, 31 deletions
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 543836b..ee9044e 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -138,6 +138,17 @@ public class AudioManager {
public static final String VOLUME_CHANGED_ACTION = "android.media.VOLUME_CHANGED_ACTION";
/**
+ * @hide Broadcast intent when a stream mute state changes.
+ * Includes the stream that changed and the new mute state
+ *
+ * @see #EXTRA_VOLUME_STREAM_TYPE
+ * @see #EXTRA_STREAM_VOLUME_MUTED
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String STREAM_MUTE_CHANGED_ACTION =
+ "android.media.STREAM_MUTE_CHANGED_ACTION";
+
+ /**
* @hide Broadcast intent when the master volume changes.
* Includes the new volume
*
@@ -221,6 +232,13 @@ public class AudioManager {
"android.media.EXTRA_MASTER_VOLUME_MUTED";
/**
+ * @hide The new stream volume mute state for the stream mute changed intent.
+ * Value is boolean
+ */
+ public static final String EXTRA_STREAM_VOLUME_MUTED =
+ "android.media.EXTRA_STREAM_VOLUME_MUTED";
+
+ /**
* Broadcast Action: Wired Headset plugged in or unplugged.
*
* You <em>cannot</em> receive this through components declared
@@ -728,11 +746,7 @@ public class AudioManager {
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
if (event.getRepeatCount() == 0) {
- if (mUseMasterVolume) {
- setMasterMute(!isMasterMute());
- } else {
- // TODO: Actually handle MUTE.
- }
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
}
break;
}
@@ -763,6 +777,9 @@ public class AudioManager {
}
mVolumeKeyUpTime = SystemClock.uptimeMillis();
break;
+ case KeyEvent.KEYCODE_VOLUME_MUTE:
+ MediaSessionLegacyHelper.getHelper(mContext).sendVolumeKeyEvent(event, false);
+ break;
}
}
diff --git a/media/java/android/media/AudioManagerInternal.java b/media/java/android/media/AudioManagerInternal.java
index d9586bc..616bdd1 100644
--- a/media/java/android/media/AudioManagerInternal.java
+++ b/media/java/android/media/AudioManagerInternal.java
@@ -15,6 +15,8 @@
*/
package android.media;
+import android.os.IBinder;
+
import com.android.server.LocalServices;
/**
@@ -39,6 +41,9 @@ public abstract class AudioManagerInternal {
public abstract void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
int uid);
+ public abstract void setMasterMuteForUid(boolean state, int flags, String callingPackage,
+ IBinder cb, int uid);
+
public abstract void setRingerModeDelegate(RingerModeDelegate delegate);
public abstract int getRingerModeInternal();
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index 9a3ec42..f1d6a0a 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -1517,12 +1517,20 @@ public class AudioService extends IAudioService.Stub {
if (mUseFixedVolume) {
return;
}
+ if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+ streamType = getActiveStreamType(streamType);
+ }
if (isStreamAffectedByMute(streamType)) {
if (streamType == AudioSystem.STREAM_MUSIC) {
setSystemAudioMute(state);
}
mStreamStates[streamType].mute(cb, state);
+
+ Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
+ intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
+ sendBroadcastToAll(intent);
}
}
@@ -1544,6 +1552,9 @@ public class AudioService extends IAudioService.Stub {
/** get stream mute state. */
public boolean isStreamMute(int streamType) {
+ if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
+ streamType = getActiveStreamType(streamType);
+ }
synchronized (VolumeStreamState.class) {
return mStreamStates[streamType].isMuted_syncVSS();
}
@@ -1651,11 +1662,16 @@ public class AudioService extends IAudioService.Stub {
/** @see AudioManager#setMasterMute(boolean, int) */
public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
+ setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
+ }
+
+ private void setMasterMuteInternal(boolean state, int flags, String callingPackage, IBinder cb,
+ int uid) {
if (mUseFixedVolume) {
return;
}
- if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
- callingPackage) != AppOpsManager.MODE_ALLOWED) {
+ if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
+ != AppOpsManager.MODE_ALLOWED) {
return;
}
if (state != AudioSystem.getMasterMute()) {
@@ -1665,6 +1681,10 @@ public class AudioService extends IAudioService.Stub {
sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
: 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
sendMasterMuteUpdate(state, flags);
+
+ Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
+ intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
+ sendBroadcastToAll(intent);
}
}
@@ -5781,6 +5801,12 @@ public class AudioService extends IAudioService.Stub {
public void setRingerModeInternal(int ringerMode, String caller) {
AudioService.this.setRingerModeInternal(ringerMode, caller);
}
+
+ @Override
+ public void setMasterMuteForUid(boolean state, int flags, String callingPackage, IBinder cb,
+ int uid) {
+ setMasterMuteInternal(state, flags, callingPackage, cb, uid);
+ }
}
//==========================================================================================
diff --git a/media/java/android/media/session/MediaSessionLegacyHelper.java b/media/java/android/media/session/MediaSessionLegacyHelper.java
index b37ee6e..4b9a929 100644
--- a/media/java/android/media/session/MediaSessionLegacyHelper.java
+++ b/media/java/android/media/session/MediaSessionLegacyHelper.java
@@ -190,6 +190,7 @@ public class MediaSessionLegacyHelper {
boolean down = keyEvent.getAction() == KeyEvent.ACTION_DOWN;
boolean up = keyEvent.getAction() == KeyEvent.ACTION_UP;
int direction = 0;
+ boolean isMute = false;
switch (keyEvent.getKeyCode()) {
case KeyEvent.KEYCODE_VOLUME_UP:
direction = AudioManager.ADJUST_RAISE;
@@ -198,15 +199,11 @@ public class MediaSessionLegacyHelper {
direction = AudioManager.ADJUST_LOWER;
break;
case KeyEvent.KEYCODE_VOLUME_MUTE:
- // TODO
+ isMute = true;
break;
}
- if ((down || up) && direction != 0) {
+ if (down || up) {
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
@@ -219,9 +216,23 @@ public class MediaSessionLegacyHelper {
flags = AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_VIBRATE;
}
}
-
- mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
- direction, flags);
+ if (direction != 0) {
+ // If this is action up we want to send a beep for non-music events
+ if (up) {
+ direction = 0;
+ }
+ mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
+ direction, flags);
+ } else if (isMute) {
+ if (down) {
+ // We need to send two volume events on down, one to mute
+ // and one to show the UI
+ mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
+ MediaSessionManager.DIRECTION_MUTE, flags);
+ }
+ mSessionManager.dispatchAdjustVolume(AudioManager.USE_DEFAULT_STREAM_TYPE,
+ 0 /* direction, causes UI to show on down */, flags);
+ }
}
}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index b4fff8f..a4ef851 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -59,6 +59,14 @@ public final class MediaSessionManager {
private Context mContext;
/**
+ * Special flag for sending the mute key to dispatchAdjustVolume used by the
+ * system.
+ *
+ * @hide
+ */
+ public static final int DIRECTION_MUTE = -99;
+
+ /**
* @hide
*/
public MediaSessionManager(Context context) {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 9440697..2c61d2c 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -35,6 +35,7 @@ import android.media.session.ISessionControllerCallback;
import android.media.session.MediaController;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
import android.media.session.ParcelableVolumeInfo;
import android.media.session.PlaybackState;
import android.media.AudioAttributes;
@@ -92,6 +93,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
private final MediaSessionService mService;
private final boolean mUseMasterVolume;
+ private final IBinder mICallback = new Binder();
private final Object mLock = new Object();
private final ArrayList<ISessionControllerCallback> mControllerCallbacks =
new ArrayList<ISessionControllerCallback>();
@@ -245,6 +247,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
if (isPlaybackActive(false) || hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
flags &= ~AudioManager.FLAG_PLAY_SOUND;
}
+ boolean isMute = direction == MediaSessionManager.DIRECTION_MUTE;
if (direction > 1) {
direction = 1;
} else if (direction < -1) {
@@ -254,29 +257,52 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
if (mUseMasterVolume) {
// If this device only uses master volume and playback is local
// just adjust the master volume and return.
- mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName, uid);
+ if (isMute) {
+ mAudioManagerInternal.setMasterMuteForUid(!mAudioManager.isMasterMute(),
+ flags, packageName, mICallback, uid);
+ } else {
+ mAudioManagerInternal.adjustMasterVolumeForUid(direction, flags, packageName,
+ uid);
+ }
return;
}
int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs);
if (useSuggested) {
if (AudioSystem.isStreamActive(stream, 0)) {
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
- flags, packageName, uid);
+ if (isMute) {
+ mAudioManager.setStreamMute(stream, !mAudioManager.isStreamMute(stream));
+ } else {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction,
+ flags, packageName, uid);
+ }
} else {
flags |= previousFlagPlaySound;
- mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
- AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
- uid);
+ if (isMute) {
+ mAudioManager.setStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE,
+ !mAudioManager.isStreamMute(AudioManager.USE_DEFAULT_STREAM_TYPE));
+ } else {
+ mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(
+ AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName,
+ uid);
+ }
}
} else {
- mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
- packageName, uid);
+ if (isMute) {
+ mAudioManager.setStreamMute(stream, !mAudioManager.isStreamMute(stream));
+ } else {
+ mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags,
+ packageName, uid);
+ }
}
} else {
if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) {
// Nothing to do, the volume cannot be changed
return;
}
+ if (isMute) {
+ Log.w(TAG, "Muting remote playback is not supported");
+ return;
+ }
mSessionCb.adjustVolume(direction);
int volumeBefore = (mOptimisticVolume < 0 ? mCurrentVolume : mOptimisticVolume);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index f11a3f9..b4ec607 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -40,6 +40,7 @@ import android.media.session.ISessionCallback;
import android.media.session.ISessionManager;
import android.media.session.MediaController.PlaybackInfo;
import android.media.session.MediaSession;
+import android.media.session.MediaSessionManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -588,6 +589,8 @@ public class MediaSessionService extends SystemService implements Monitor {
"android.media.AudioService.WAKELOCK_ACQUIRED";
private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; // magic number
+ private final IBinder mICallback = new Binder();
+
private boolean mVoiceButtonDown = false;
private boolean mVoiceButtonHandled = false;
@@ -720,8 +723,7 @@ public class MediaSessionService extends SystemService implements Monitor {
}
@Override
- public void dispatchAdjustVolume(int suggestedStream, int delta, int flags)
- throws RemoteException {
+ public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final long token = Binder.clearCallingIdentity();
@@ -828,11 +830,21 @@ public class MediaSessionService extends SystemService implements Monitor {
}
try {
if (mUseMasterVolume) {
- mAudioService.adjustMasterVolume(direction, flags,
- getContext().getOpPackageName());
+ if (direction == MediaSessionManager.DIRECTION_MUTE) {
+ mAudioService.setMasterMute(!mAudioService.isMasterMute(), flags,
+ getContext().getOpPackageName(), mICallback);
+ } else {
+ mAudioService.adjustMasterVolume(direction, flags,
+ getContext().getOpPackageName());
+ }
} else {
- mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream, flags,
- getContext().getOpPackageName());
+ if (direction == MediaSessionManager.DIRECTION_MUTE) {
+ mAudioService.setStreamMute(suggestedStream,
+ !mAudioService.isStreamMute(suggestedStream), mICallback);
+ } else {
+ mAudioService.adjustSuggestedStreamVolume(direction, suggestedStream,
+ flags, getContext().getOpPackageName());
+ }
}
} catch (RemoteException e) {
Log.e(TAG, "Error adjusting default volume.", e);
@@ -841,7 +853,7 @@ public class MediaSessionService extends SystemService implements Monitor {
session.adjustVolume(direction, flags, getContext().getPackageName(),
UserHandle.myUserId(), true);
if (session.getPlaybackType() == PlaybackInfo.PLAYBACK_TYPE_REMOTE
- && mRvc != null) {
+ && mRvc != null && direction != MediaSessionManager.DIRECTION_MUTE) {
try {
mRvc.remoteVolumeChanged(session.getControllerBinder(), flags);
} catch (Exception e) {