APC: expose the mute state for system APIs

Add the possibility for system APIs to query if an app is muted and what
are the sources that are muting a specific player/track.

Test: atest android.media.audio.cts.AudioPlaybackConfigurationTest
Bug: 248145607
Change-Id: If40faa860c2663c9ca8436df0e7b8c10464d535b
This commit is contained in:
Vlad Popa
2022-09-23 21:04:07 +02:00
parent 2158b4f92d
commit 39ca328582
3 changed files with 83 additions and 42 deletions

View File

@@ -6345,12 +6345,21 @@ package android.media {
public final class AudioPlaybackConfiguration implements android.os.Parcelable {
method public int getClientPid();
method public int getClientUid();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMutedBy();
method public int getPlayerInterfaceId();
method public android.media.PlayerProxy getPlayerProxy();
method public int getPlayerState();
method public int getPlayerType();
method @IntRange(from=0) public int getSessionId();
method public boolean isActive();
method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isMuted();
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_APP_OPS = 8; // 0x8
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_CLIENT_VOLUME = 16; // 0x10
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_MASTER = 1; // 0x1
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_MUTED = 4; // 0x4
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_STREAM_VOLUME = 2; // 0x2
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_UNKNOWN = -1; // 0xffffffff
field @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public static final int MUTED_BY_VOLUME_SHAPER = 32; // 0x20
field public static final int PLAYER_STATE_IDLE = 1; // 0x1
field public static final int PLAYER_STATE_PAUSED = 3; // 0x3
field public static final int PLAYER_STATE_RELEASED = 0; // 0x0

View File

@@ -23,6 +23,7 @@ import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.os.Binder;
import android.os.IBinder;
@@ -220,46 +221,59 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/**
* @hide
* Mute state used for anonymization.
* Mute state used for the initial state and when API is accessed without permission.
*/
public static final int PLAYER_MUTE_INVALID = -1;
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_UNKNOWN = -1;
/**
* @hide
* Flag used when muted by master volume.
*/
public static final int PLAYER_MUTE_MASTER = (1 << 0);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_MASTER = (1 << 0);
/**
* @hide
* Flag used when muted by stream volume.
*/
public static final int PLAYER_MUTE_STREAM_VOLUME = (1 << 1);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_STREAM_VOLUME = (1 << 1);
/**
* @hide
* Flag used when muted by stream mute.
*/
public static final int PLAYER_MUTE_STREAM_MUTED = (1 << 2);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_STREAM_MUTED = (1 << 2);
/**
* @hide
* Flag used when playback is restricted by AppOps manager with OP_PLAY_AUDIO.
* Flag used when playback is muted by AppOpsManager#OP_PLAY_AUDIO.
*/
public static final int PLAYER_MUTE_PLAYBACK_RESTRICTED = (1 << 3);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_APP_OPS = (1 << 3);
/**
* @hide
* Flag used when muted by client volume.
*/
public static final int PLAYER_MUTE_CLIENT_VOLUME = (1 << 4);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_CLIENT_VOLUME = (1 << 4);
/**
* @hide
* Flag used when muted by volume shaper.
*/
public static final int PLAYER_MUTE_VOLUME_SHAPER = (1 << 5);
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public static final int MUTED_BY_VOLUME_SHAPER = (1 << 5);
/** @hide */
@IntDef(
flag = true,
value = {PLAYER_MUTE_MASTER, PLAYER_MUTE_STREAM_VOLUME, PLAYER_MUTE_STREAM_MUTED,
PLAYER_MUTE_PLAYBACK_RESTRICTED, PLAYER_MUTE_CLIENT_VOLUME,
PLAYER_MUTE_VOLUME_SHAPER})
value = {MUTED_BY_MASTER, MUTED_BY_STREAM_VOLUME, MUTED_BY_STREAM_MUTED,
MUTED_BY_APP_OPS, MUTED_BY_CLIENT_VOLUME, MUTED_BY_VOLUME_SHAPER})
@Retention(RetentionPolicy.SOURCE)
public @interface PlayerMuteEvent {
}
@@ -303,7 +317,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
mPlayerType = pic.mPlayerType;
mClientUid = uid;
mClientPid = pid;
mMutedState = PLAYER_MUTE_INVALID;
mMutedState = MUTED_BY_UNKNOWN;
mDeviceId = PLAYER_DEVICEID_INVALID;
mPlayerState = PLAYER_STATE_IDLE;
mPlayerAttr = pic.mAttributes;
@@ -352,7 +366,7 @@ public final class AudioPlaybackConfiguration implements Parcelable {
anonymCopy.mPlayerAttr = builder.build();
anonymCopy.mDeviceId = in.mDeviceId;
// anonymized data
anonymCopy.mMutedState = PLAYER_MUTE_INVALID;
anonymCopy.mMutedState = MUTED_BY_UNKNOWN;
anonymCopy.mPlayerType = PLAYER_TYPE_UNKNOWN;
anonymCopy.mClientUid = PLAYER_UPID_INVALID;
anonymCopy.mClientPid = PLAYER_UPID_INVALID;
@@ -413,9 +427,27 @@ public final class AudioPlaybackConfiguration implements Parcelable {
/**
* @hide
* @return the mute state as a combination of {@link PlayerMuteEvent} flags
* Used for determining if the current player is muted.
* <br>Note that if this result is true then {@link #getMutedBy} will be > 0.
* @return {@code true} if the player associated with this configuration has been muted (by any
* given MUTED_BY_* source event) or {@code false} otherwise.
*/
@PlayerMuteEvent public int getMutedState() {
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
public boolean isMuted() {
return mMutedState != 0 && mMutedState != MUTED_BY_UNKNOWN;
}
/**
* @hide
* Returns a bitmask expressing the mute state as a combination of MUTED_BY_* flags.
* <br>Note that if the mute state is not set the result will be {@link #MUTED_BY_UNKNOWN}. A
* value of 0 represents a player which is not muted.
* @return the mute state.
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
@PlayerMuteEvent public int getMutedBy() {
return mMutedState;
}
@@ -570,14 +602,14 @@ public final class AudioPlaybackConfiguration implements Parcelable {
}
private boolean isMuteAffectingActiveState() {
if (mMutedState == PLAYER_MUTE_INVALID) {
if (mMutedState == MUTED_BY_UNKNOWN) {
// mute state is not set, therefore it will not affect the active state
return false;
}
return (mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0
|| (mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0
|| (mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0;
return (mMutedState & MUTED_BY_CLIENT_VOLUME) != 0
|| (mMutedState & MUTED_BY_VOLUME_SHAPER) != 0
|| (mMutedState & MUTED_BY_APP_OPS) != 0;
}
/**
@@ -694,27 +726,27 @@ public final class AudioPlaybackConfiguration implements Parcelable {
"/").append(mClientPid).append(" state:").append(
toLogFriendlyPlayerState(mPlayerState)).append(" attr:").append(mPlayerAttr).append(
" sessionId:").append(mSessionId).append(" mutedState:");
if (mMutedState == PLAYER_MUTE_INVALID) {
apcToString.append("invalid ");
if (mMutedState == MUTED_BY_UNKNOWN) {
apcToString.append("unknown ");
} else if (mMutedState == 0) {
apcToString.append("none ");
} else {
if ((mMutedState & PLAYER_MUTE_MASTER) != 0) {
if ((mMutedState & MUTED_BY_MASTER) != 0) {
apcToString.append("master ");
}
if ((mMutedState & PLAYER_MUTE_STREAM_VOLUME) != 0) {
if ((mMutedState & MUTED_BY_STREAM_VOLUME) != 0) {
apcToString.append("streamVolume ");
}
if ((mMutedState & PLAYER_MUTE_STREAM_MUTED) != 0) {
if ((mMutedState & MUTED_BY_STREAM_MUTED) != 0) {
apcToString.append("streamMute ");
}
if ((mMutedState & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
apcToString.append("playbackRestricted ");
if ((mMutedState & MUTED_BY_APP_OPS) != 0) {
apcToString.append("appOps ");
}
if ((mMutedState & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
if ((mMutedState & MUTED_BY_CLIENT_VOLUME) != 0) {
apcToString.append("clientVolume ");
}
if ((mMutedState & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
if ((mMutedState & MUTED_BY_VOLUME_SHAPER) != 0) {
apcToString.append("volumeShaper ");
}
}

View File

@@ -17,12 +17,12 @@
package com.android.server.audio;
import static android.media.AudioPlaybackConfiguration.EXTRA_PLAYER_EVENT_MUTE;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_CLIENT_VOLUME;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_MASTER;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_PLAYBACK_RESTRICTED;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_STREAM_MUTED;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_STREAM_VOLUME;
import static android.media.AudioPlaybackConfiguration.PLAYER_MUTE_VOLUME_SHAPER;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_APP_OPS;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_CLIENT_VOLUME;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_MASTER;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_MUTED;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_STREAM_VOLUME;
import static android.media.AudioPlaybackConfiguration.MUTED_BY_VOLUME_SHAPER;
import static android.media.AudioPlaybackConfiguration.PLAYER_PIID_INVALID;
import static android.media.AudioPlaybackConfiguration.PLAYER_UPDATE_MUTED;
@@ -1155,22 +1155,22 @@ public final class PlaybackActivityMonitor
if (mEventValue <= 0) {
builder.append("none ");
} else {
if ((mEventValue & PLAYER_MUTE_MASTER) != 0) {
if ((mEventValue & MUTED_BY_MASTER) != 0) {
builder.append("masterMute ");
}
if ((mEventValue & PLAYER_MUTE_STREAM_VOLUME) != 0) {
if ((mEventValue & MUTED_BY_STREAM_VOLUME) != 0) {
builder.append("streamVolume ");
}
if ((mEventValue & PLAYER_MUTE_STREAM_MUTED) != 0) {
if ((mEventValue & MUTED_BY_STREAM_MUTED) != 0) {
builder.append("streamMute ");
}
if ((mEventValue & PLAYER_MUTE_PLAYBACK_RESTRICTED) != 0) {
builder.append("playbackRestricted ");
if ((mEventValue & MUTED_BY_APP_OPS) != 0) {
builder.append("appOps ");
}
if ((mEventValue & PLAYER_MUTE_CLIENT_VOLUME) != 0) {
if ((mEventValue & MUTED_BY_CLIENT_VOLUME) != 0) {
builder.append("clientVolume ");
}
if ((mEventValue & PLAYER_MUTE_VOLUME_SHAPER) != 0) {
if ((mEventValue & MUTED_BY_VOLUME_SHAPER) != 0) {
builder.append("volumeShaper ");
}
}