Merge "AudioDeviceVolumeManager and VolumeInfo API changes" into tm-qpr-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
dcb2710560
@@ -115,6 +115,7 @@ import android.location.CountryDetector;
|
||||
import android.location.ICountryDetector;
|
||||
import android.location.ILocationManager;
|
||||
import android.location.LocationManager;
|
||||
import android.media.AudioDeviceVolumeManager;
|
||||
import android.media.AudioManager;
|
||||
import android.media.MediaFrameworkInitializer;
|
||||
import android.media.MediaFrameworkPlatformInitializer;
|
||||
@@ -339,6 +340,13 @@ public final class SystemServiceRegistry {
|
||||
return new AudioManager(ctx);
|
||||
}});
|
||||
|
||||
registerService(Context.AUDIO_DEVICE_VOLUME_SERVICE, AudioDeviceVolumeManager.class,
|
||||
new CachedServiceFetcher<AudioDeviceVolumeManager>() {
|
||||
@Override
|
||||
public AudioDeviceVolumeManager createService(ContextImpl ctx) {
|
||||
return new AudioDeviceVolumeManager(ctx);
|
||||
}});
|
||||
|
||||
registerService(Context.MEDIA_ROUTER_SERVICE, MediaRouter.class,
|
||||
new CachedServiceFetcher<MediaRouter>() {
|
||||
@Override
|
||||
|
||||
@@ -3846,6 +3846,7 @@ public abstract class Context {
|
||||
WIFI_RTT_RANGING_SERVICE,
|
||||
NSD_SERVICE,
|
||||
AUDIO_SERVICE,
|
||||
AUDIO_DEVICE_VOLUME_SERVICE,
|
||||
AUTH_SERVICE,
|
||||
FINGERPRINT_SERVICE,
|
||||
//@hide: FACE_SERVICE,
|
||||
@@ -4686,6 +4687,17 @@ public abstract class Context {
|
||||
*/
|
||||
public static final String AUDIO_SERVICE = "audio";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Use with {@link #getSystemService(String)} to retrieve a
|
||||
* {@link android.media.AudioDeviceVolumeManager} for handling management of audio device
|
||||
* (e.g. speaker, USB headset) volume.
|
||||
*
|
||||
* @see #getSystemService(String)
|
||||
* @see android.media.AudioDeviceVolumeManager
|
||||
*/
|
||||
public static final String AUDIO_DEVICE_VOLUME_SERVICE = "audio_device_volume";
|
||||
|
||||
/**
|
||||
* Use with {@link #getSystemService(String)} to retrieve a {@link
|
||||
* android.media.MediaTranscodingManager} for transcoding media.
|
||||
|
||||
@@ -41,8 +41,7 @@ import java.util.concurrent.Executor;
|
||||
*/
|
||||
public class AudioDeviceVolumeManager {
|
||||
|
||||
// define when using Log.*
|
||||
//private static final String TAG = "AudioDeviceVolumeManager";
|
||||
private static final String TAG = "AudioDeviceVolumeManager";
|
||||
|
||||
/** Indicates no special treatment in the handling of the volume adjustment */
|
||||
public static final int ADJUST_MODE_NORMAL = 0;
|
||||
@@ -62,11 +61,15 @@ public class AudioDeviceVolumeManager {
|
||||
private static IAudioService sService;
|
||||
|
||||
private final @NonNull String mPackageName;
|
||||
private final @Nullable String mAttributionTag;
|
||||
|
||||
public AudioDeviceVolumeManager(Context context) {
|
||||
/**
|
||||
* @hide
|
||||
* Constructor
|
||||
* @param context the Context for the device volume operations
|
||||
*/
|
||||
public AudioDeviceVolumeManager(@NonNull Context context) {
|
||||
Objects.requireNonNull(context);
|
||||
mPackageName = context.getApplicationContext().getOpPackageName();
|
||||
mAttributionTag = context.getApplicationContext().getAttributionTag();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -308,13 +311,36 @@ public class AudioDeviceVolumeManager {
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada) {
|
||||
try {
|
||||
getService().setDeviceVolume(vi, ada, mPackageName, mAttributionTag);
|
||||
getService().setDeviceVolume(vi, ada, mPackageName);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the volume on the given audio device for the given volume information.
|
||||
* For instance if using a {@link VolumeInfo} configured for {@link AudioManager#STREAM_ALARM},
|
||||
* it will return the alarm volume. When no volume index has ever been set for the given
|
||||
* device, the default volume will be returned (the volume setting that would have been
|
||||
* applied if playback for that use case had started).
|
||||
* @param vi the volume information, only stream-based volumes are supported. Information
|
||||
* other than the stream type is ignored.
|
||||
* @param ada the device for which volume is to be retrieved
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
|
||||
@NonNull AudioDeviceAttributes ada) {
|
||||
try {
|
||||
return getService().getDeviceVolume(vi, ada, mPackageName);
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
}
|
||||
return VolumeInfo.getDefaultVolumeInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Return human-readable name for volume behavior
|
||||
* @param behavior one of the volume behaviors defined in AudioManager
|
||||
* @return a string for the given behavior
|
||||
|
||||
@@ -1212,7 +1212,13 @@ public class AudioManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isPublicStreamType(int streamType) {
|
||||
/**
|
||||
* @hide
|
||||
* Checks whether a stream type is part of the public SDK
|
||||
* @param streamType
|
||||
* @return true if the stream type is available in SDK
|
||||
*/
|
||||
public static boolean isPublicStreamType(int streamType) {
|
||||
switch (streamType) {
|
||||
case STREAM_VOICE_CALL:
|
||||
case STREAM_SYSTEM:
|
||||
|
||||
@@ -99,7 +99,10 @@ interface IAudioService {
|
||||
in String callingPackage, in String attributionTag);
|
||||
|
||||
void setDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
|
||||
in String callingPackage, in String attributionTag);
|
||||
in String callingPackage);
|
||||
|
||||
VolumeInfo getDeviceVolume(in VolumeInfo vi, in AudioDeviceAttributes ada,
|
||||
in String callingPackage);
|
||||
|
||||
oneway void handleVolumeKey(in KeyEvent event, boolean isOnTv,
|
||||
String callingPackage, String caller);
|
||||
|
||||
@@ -27,7 +27,6 @@ import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -35,8 +34,9 @@ import java.util.Objects;
|
||||
* A class to represent type of volume information.
|
||||
* Can be used to represent volume associated with a stream type or {@link AudioVolumeGroup}.
|
||||
* Volume index is optional when used to represent a category of volume.
|
||||
* Index ranges are supported too, making the representation of volume changes agnostic to the
|
||||
* range (e.g. can be used to map BT A2DP absolute volume range to internal range).
|
||||
* Volume ranges are supported too, making the representation of volume changes agnostic
|
||||
* regarding the range of values that are supported (e.g. can be used to map BT A2DP absolute
|
||||
* volume range to internal range).
|
||||
*
|
||||
* Note: this class is not yet part of the SystemApi but is intended to be gradually introduced
|
||||
* particularly in parts of the audio framework that suffer from code ambiguity when
|
||||
@@ -46,25 +46,27 @@ public final class VolumeInfo implements Parcelable {
|
||||
private static final String TAG = "VolumeInfo";
|
||||
|
||||
private final boolean mUsesStreamType; // false implies AudioVolumeGroup is used
|
||||
private final boolean mHasMuteCommand;
|
||||
private final boolean mIsMuted;
|
||||
private final int mVolIndex;
|
||||
private final int mMinVolIndex;
|
||||
private final int mMaxVolIndex;
|
||||
private final int mVolGroupId;
|
||||
private final int mStreamType;
|
||||
private final @Nullable AudioVolumeGroup mVolGroup;
|
||||
private final @AudioManager.PublicStreamTypes int mStreamType;
|
||||
|
||||
private static IAudioService sService;
|
||||
private static VolumeInfo sDefaultVolumeInfo;
|
||||
|
||||
private VolumeInfo(boolean usesStreamType, boolean isMuted, int volIndex,
|
||||
int minVolIndex, int maxVolIndex,
|
||||
int volGroupId, int streamType) {
|
||||
private VolumeInfo(boolean usesStreamType, boolean hasMuteCommand, boolean isMuted,
|
||||
int volIndex, int minVolIndex, int maxVolIndex,
|
||||
AudioVolumeGroup volGroup, int streamType) {
|
||||
mUsesStreamType = usesStreamType;
|
||||
mHasMuteCommand = hasMuteCommand;
|
||||
mIsMuted = isMuted;
|
||||
mVolIndex = volIndex;
|
||||
mMinVolIndex = minVolIndex;
|
||||
mMaxVolIndex = maxVolIndex;
|
||||
mVolGroupId = volGroupId;
|
||||
mVolGroup = volGroup;
|
||||
mStreamType = streamType;
|
||||
}
|
||||
|
||||
@@ -81,8 +83,10 @@ public final class VolumeInfo implements Parcelable {
|
||||
/**
|
||||
* Returns the associated stream type, or will throw if {@link #hasStreamType()} returned false.
|
||||
* @return a stream type value, see AudioManager.STREAM_*
|
||||
* @throws IllegalStateException when called on a VolumeInfo not configured for
|
||||
* stream types.
|
||||
*/
|
||||
public int getStreamType() {
|
||||
public @AudioManager.PublicStreamTypes int getStreamType() {
|
||||
if (!mUsesStreamType) {
|
||||
throw new IllegalStateException("VolumeInfo doesn't use stream types");
|
||||
}
|
||||
@@ -101,24 +105,28 @@ public final class VolumeInfo implements Parcelable {
|
||||
/**
|
||||
* Returns the associated volume group, or will throw if {@link #hasVolumeGroup()} returned
|
||||
* false.
|
||||
* @return the volume group corresponding to this VolumeInfo, or null if an error occurred
|
||||
* in the volume group management
|
||||
* @return the volume group corresponding to this VolumeInfo
|
||||
* @throws IllegalStateException when called on a VolumeInfo not configured for
|
||||
* volume groups.
|
||||
*/
|
||||
public @Nullable AudioVolumeGroup getVolumeGroup() {
|
||||
public @NonNull AudioVolumeGroup getVolumeGroup() {
|
||||
if (mUsesStreamType) {
|
||||
throw new IllegalStateException("VolumeInfo doesn't use AudioVolumeGroup");
|
||||
}
|
||||
List<AudioVolumeGroup> volGroups = AudioVolumeGroup.getAudioVolumeGroups();
|
||||
for (AudioVolumeGroup group : volGroups) {
|
||||
if (group.getId() == mVolGroupId) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return mVolGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this instance is conveying a mute state.
|
||||
* Return whether this instance is conveying a mute state
|
||||
* @return true if the muted state was explicitly set for this instance
|
||||
*/
|
||||
public boolean hasMuteCommand() {
|
||||
return mHasMuteCommand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this instance is conveying a mute state that was explicitly set
|
||||
* by {@link Builder#setMuted(boolean)}, false otherwise
|
||||
* @return true if the volume state is muted
|
||||
*/
|
||||
public boolean isMuted() {
|
||||
@@ -185,18 +193,21 @@ public final class VolumeInfo implements Parcelable {
|
||||
*/
|
||||
public static final class Builder {
|
||||
private boolean mUsesStreamType = true; // false implies AudioVolumeGroup is used
|
||||
private int mStreamType = AudioManager.STREAM_MUSIC;
|
||||
private @AudioManager.PublicStreamTypes int mStreamType = AudioManager.STREAM_MUSIC;
|
||||
private boolean mHasMuteCommand = false;
|
||||
private boolean mIsMuted = false;
|
||||
private int mVolIndex = INDEX_NOT_SET;
|
||||
private int mMinVolIndex = INDEX_NOT_SET;
|
||||
private int mMaxVolIndex = INDEX_NOT_SET;
|
||||
private int mVolGroupId = -Integer.MIN_VALUE;
|
||||
private @Nullable AudioVolumeGroup mVolGroup;
|
||||
|
||||
/**
|
||||
* Builder constructor for stream type-based VolumeInfo
|
||||
*/
|
||||
public Builder(int streamType) {
|
||||
// TODO validate stream type
|
||||
public Builder(@AudioManager.PublicStreamTypes int streamType) {
|
||||
if (!AudioManager.isPublicStreamType(streamType)) {
|
||||
throw new IllegalArgumentException("Not a valid public stream type " + streamType);
|
||||
}
|
||||
mUsesStreamType = true;
|
||||
mStreamType = streamType;
|
||||
}
|
||||
@@ -208,7 +219,7 @@ public final class VolumeInfo implements Parcelable {
|
||||
Objects.requireNonNull(volGroup);
|
||||
mUsesStreamType = false;
|
||||
mStreamType = -Integer.MIN_VALUE;
|
||||
mVolGroupId = volGroup.getId();
|
||||
mVolGroup = volGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -219,11 +230,12 @@ public final class VolumeInfo implements Parcelable {
|
||||
Objects.requireNonNull(info);
|
||||
mUsesStreamType = info.mUsesStreamType;
|
||||
mStreamType = info.mStreamType;
|
||||
mHasMuteCommand = info.mHasMuteCommand;
|
||||
mIsMuted = info.mIsMuted;
|
||||
mVolIndex = info.mVolIndex;
|
||||
mMinVolIndex = info.mMinVolIndex;
|
||||
mMaxVolIndex = info.mMaxVolIndex;
|
||||
mVolGroupId = info.mVolGroupId;
|
||||
mVolGroup = info.mVolGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,6 +244,7 @@ public final class VolumeInfo implements Parcelable {
|
||||
* @return the same builder instance
|
||||
*/
|
||||
public @NonNull Builder setMuted(boolean isMuted) {
|
||||
mHasMuteCommand = true;
|
||||
mIsMuted = isMuted;
|
||||
return this;
|
||||
}
|
||||
@@ -241,7 +254,6 @@ public final class VolumeInfo implements Parcelable {
|
||||
* @param volIndex a 0 or greater value, or {@link #INDEX_NOT_SET} if unknown
|
||||
* @return the same builder instance
|
||||
*/
|
||||
// TODO should we allow muted true + volume index set? (useful when toggling mute on/off?)
|
||||
public @NonNull Builder setVolumeIndex(int volIndex) {
|
||||
if (volIndex != INDEX_NOT_SET && volIndex < 0) {
|
||||
throw new IllegalArgumentException("Volume index cannot be negative");
|
||||
@@ -296,9 +308,9 @@ public final class VolumeInfo implements Parcelable {
|
||||
throw new IllegalArgumentException("Min volume index:" + mMinVolIndex
|
||||
+ " greater than max index:" + mMaxVolIndex);
|
||||
}
|
||||
return new VolumeInfo(mUsesStreamType, mIsMuted,
|
||||
return new VolumeInfo(mUsesStreamType, mHasMuteCommand, mIsMuted,
|
||||
mVolIndex, mMinVolIndex, mMaxVolIndex,
|
||||
mVolGroupId, mStreamType);
|
||||
mVolGroup, mStreamType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,8 +318,8 @@ public final class VolumeInfo implements Parcelable {
|
||||
// Parcelable
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mUsesStreamType, mStreamType, mIsMuted,
|
||||
mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroupId);
|
||||
return Objects.hash(mUsesStreamType, mHasMuteCommand, mStreamType, mIsMuted,
|
||||
mVolIndex, mMinVolIndex, mMaxVolIndex, mVolGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -318,19 +330,20 @@ public final class VolumeInfo implements Parcelable {
|
||||
VolumeInfo that = (VolumeInfo) o;
|
||||
return ((mUsesStreamType == that.mUsesStreamType)
|
||||
&& (mStreamType == that.mStreamType)
|
||||
&& (mIsMuted == that.mIsMuted)
|
||||
&& (mVolIndex == that.mVolIndex)
|
||||
&& (mMinVolIndex == that.mMinVolIndex)
|
||||
&& (mMaxVolIndex == that.mMaxVolIndex)
|
||||
&& (mVolGroupId == that.mVolGroupId));
|
||||
&& (mHasMuteCommand == that.mHasMuteCommand)
|
||||
&& (mIsMuted == that.mIsMuted)
|
||||
&& (mVolIndex == that.mVolIndex)
|
||||
&& (mMinVolIndex == that.mMinVolIndex)
|
||||
&& (mMaxVolIndex == that.mMaxVolIndex)
|
||||
&& Objects.equals(mVolGroup, that.mVolGroup));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new String("VolumeInfo:"
|
||||
+ (mUsesStreamType ? (" streamType:" + mStreamType)
|
||||
: (" volGroupId" + mVolGroupId))
|
||||
+ " muted:" + mIsMuted
|
||||
: (" volGroup:" + mVolGroup))
|
||||
+ (mHasMuteCommand ? (" muted:" + mIsMuted) : ("[no mute cmd]"))
|
||||
+ ((mVolIndex != INDEX_NOT_SET) ? (" volIndex:" + mVolIndex) : "")
|
||||
+ ((mMinVolIndex != INDEX_NOT_SET) ? (" min:" + mMinVolIndex) : "")
|
||||
+ ((mMaxVolIndex != INDEX_NOT_SET) ? (" max:" + mMaxVolIndex) : ""));
|
||||
@@ -345,21 +358,29 @@ public final class VolumeInfo implements Parcelable {
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeBoolean(mUsesStreamType);
|
||||
dest.writeInt(mStreamType);
|
||||
dest.writeBoolean(mHasMuteCommand);
|
||||
dest.writeBoolean(mIsMuted);
|
||||
dest.writeInt(mVolIndex);
|
||||
dest.writeInt(mMinVolIndex);
|
||||
dest.writeInt(mMaxVolIndex);
|
||||
dest.writeInt(mVolGroupId);
|
||||
if (!mUsesStreamType) {
|
||||
mVolGroup.writeToParcel(dest, 0 /*ignored*/);
|
||||
}
|
||||
}
|
||||
|
||||
private VolumeInfo(@NonNull Parcel in) {
|
||||
mUsesStreamType = in.readBoolean();
|
||||
mStreamType = in.readInt();
|
||||
mHasMuteCommand = in.readBoolean();
|
||||
mIsMuted = in.readBoolean();
|
||||
mVolIndex = in.readInt();
|
||||
mMinVolIndex = in.readInt();
|
||||
mMaxVolIndex = in.readInt();
|
||||
mVolGroupId = in.readInt();
|
||||
if (!mUsesStreamType) {
|
||||
mVolGroup = AudioVolumeGroup.CREATOR.createFromParcel(in);
|
||||
} else {
|
||||
mVolGroup = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final @NonNull Parcelable.Creator<VolumeInfo> CREATOR =
|
||||
|
||||
@@ -3599,6 +3599,18 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
// TODO enforce MODIFY_AUDIO_SYSTEM_SETTINGS when defined
|
||||
private void enforceModifyAudioRoutingOrSystemSettingsPermission() {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)
|
||||
!= PackageManager.PERMISSION_GRANTED
|
||||
/*&& mContext.checkCallingOrSelfPermission(
|
||||
android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS)
|
||||
!= PackageManager.PERMISSION_DENIED*/) {
|
||||
throw new SecurityException(
|
||||
"Missing MODIFY_AUDIO_ROUTING or MODIFY_AUDIO_SYSTEM_SETTINGS permission");
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceAccessUltrasoundPermission() {
|
||||
if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.ACCESS_ULTRASOUND)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
@@ -3703,10 +3715,12 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
|
||||
/** @see AudioDeviceVolumeManager#setDeviceVolume(VolumeInfo, AudioDeviceAttributes)
|
||||
* Part of service interface, check permissions and parameters here */
|
||||
* Part of service interface, check permissions and parameters here
|
||||
* Note calling package is for logging purposes only, not to be trusted
|
||||
*/
|
||||
public void setDeviceVolume(@NonNull VolumeInfo vi, @NonNull AudioDeviceAttributes ada,
|
||||
@NonNull String callingPackage, @Nullable String attributionTag) {
|
||||
enforceModifyAudioRoutingPermission();
|
||||
@NonNull String callingPackage) {
|
||||
enforceModifyAudioRoutingOrSystemSettingsPermission();
|
||||
Objects.requireNonNull(vi);
|
||||
Objects.requireNonNull(ada);
|
||||
Objects.requireNonNull(callingPackage);
|
||||
@@ -3719,8 +3733,20 @@ public class AudioService extends IAudioService.Stub
|
||||
return;
|
||||
}
|
||||
int index = vi.getVolumeIndex();
|
||||
if (index == VolumeInfo.INDEX_NOT_SET) {
|
||||
throw new IllegalArgumentException("changing device volume requires a volume index");
|
||||
if (index == VolumeInfo.INDEX_NOT_SET && !vi.hasMuteCommand()) {
|
||||
throw new IllegalArgumentException(
|
||||
"changing device volume requires a volume index or mute command");
|
||||
}
|
||||
|
||||
// TODO handle unmuting of current audio device
|
||||
// if a stream is not muted but the VolumeInfo is for muting, set the volume index
|
||||
// for the device to min volume
|
||||
if (vi.hasMuteCommand() && vi.isMuted() && !isStreamMute(vi.getStreamType())) {
|
||||
setStreamVolumeWithAttributionInt(vi.getStreamType(),
|
||||
mStreamStates[vi.getStreamType()].getMinIndex(),
|
||||
/*flags*/ 0,
|
||||
ada, callingPackage, null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vi.getMinVolumeIndex() == VolumeInfo.INDEX_NOT_SET
|
||||
@@ -3742,7 +3768,7 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
}
|
||||
setStreamVolumeWithAttributionInt(vi.getStreamType(), index, /*flags*/ 0,
|
||||
ada, callingPackage, attributionTag);
|
||||
ada, callingPackage, null);
|
||||
}
|
||||
|
||||
/** Retain API for unsupported app usage */
|
||||
@@ -4648,6 +4674,40 @@ public class AudioService extends IAudioService.Stub
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see AudioDeviceVolumeManager#getDeviceVolume(VolumeInfo, AudioDeviceAttributes)
|
||||
*/
|
||||
public @NonNull VolumeInfo getDeviceVolume(@NonNull VolumeInfo vi,
|
||||
@NonNull AudioDeviceAttributes ada, @NonNull String callingPackage) {
|
||||
enforceModifyAudioRoutingOrSystemSettingsPermission();
|
||||
Objects.requireNonNull(vi);
|
||||
Objects.requireNonNull(ada);
|
||||
Objects.requireNonNull(callingPackage);
|
||||
if (!vi.hasStreamType()) {
|
||||
Log.e(TAG, "Unsupported non-stream type based VolumeInfo", new Exception());
|
||||
return getDefaultVolumeInfo();
|
||||
}
|
||||
|
||||
int streamType = vi.getStreamType();
|
||||
final VolumeInfo.Builder vib = new VolumeInfo.Builder(vi);
|
||||
vib.setMinVolumeIndex((mStreamStates[streamType].mIndexMin + 5) / 10);
|
||||
vib.setMaxVolumeIndex((mStreamStates[streamType].mIndexMax + 5) / 10);
|
||||
synchronized (VolumeStreamState.class) {
|
||||
final int index;
|
||||
if (isFixedVolumeDevice(ada.getInternalType())) {
|
||||
index = (mStreamStates[streamType].mIndexMax + 5) / 10;
|
||||
} else {
|
||||
index = (mStreamStates[streamType].getIndex(ada.getInternalType()) + 5) / 10;
|
||||
}
|
||||
vib.setVolumeIndex(index);
|
||||
// only set as a mute command if stream muted
|
||||
if (mStreamStates[streamType].mIsMuted) {
|
||||
vib.setMuted(true);
|
||||
}
|
||||
return vib.build();
|
||||
}
|
||||
}
|
||||
|
||||
/** @see AudioManager#getStreamMaxVolume(int) */
|
||||
public int getStreamMaxVolume(int streamType) {
|
||||
ensureValidStreamType(streamType);
|
||||
@@ -4686,7 +4746,6 @@ public class AudioService extends IAudioService.Stub
|
||||
sDefaultVolumeInfo = new VolumeInfo.Builder(AudioSystem.STREAM_MUSIC)
|
||||
.setMinVolumeIndex(getStreamMinVolume(AudioSystem.STREAM_MUSIC))
|
||||
.setMaxVolumeIndex(getStreamMaxVolume(AudioSystem.STREAM_MUSIC))
|
||||
.setMuted(false)
|
||||
.build();
|
||||
}
|
||||
return sDefaultVolumeInfo;
|
||||
|
||||
@@ -27,18 +27,18 @@ import android.media.AudioManager;
|
||||
import android.media.AudioSystem;
|
||||
import android.media.VolumeInfo;
|
||||
import android.os.test.TestLooper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.test.InstrumentationRegistry;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AudioDeviceVolumeManagerTest {
|
||||
private static final String TAG = "AudioDeviceVolumeManagerTest";
|
||||
|
||||
private static final AudioDeviceAttributes DEVICE_SPEAKER_OUT = new AudioDeviceAttributes(
|
||||
AudioDeviceAttributes.ROLE_OUTPUT, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER, "");
|
||||
|
||||
private Context mContext;
|
||||
private String mPackageName;
|
||||
private AudioSystemAdapter mSpyAudioSystem;
|
||||
@@ -84,14 +84,20 @@ public class AudioDeviceVolumeManagerTest {
|
||||
final AudioDeviceAttributes usbDevice = new AudioDeviceAttributes(
|
||||
/*native type*/ AudioSystem.DEVICE_OUT_USB_DEVICE, /*address*/ "bla");
|
||||
|
||||
mAudioService.setDeviceVolume(volMin, usbDevice, mPackageName, TAG);
|
||||
mAudioService.setDeviceVolume(volMin, usbDevice, mPackageName);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
|
||||
AudioManager.STREAM_MUSIC, minIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
|
||||
|
||||
mAudioService.setDeviceVolume(volMid, usbDevice, mPackageName, TAG);
|
||||
mAudioService.setDeviceVolume(volMid, usbDevice, mPackageName);
|
||||
mTestLooper.dispatchAll();
|
||||
verify(mSpyAudioSystem, atLeast(1)).setStreamVolumeIndexAS(
|
||||
AudioManager.STREAM_MUSIC, midIndex, AudioSystem.DEVICE_OUT_USB_DEVICE);
|
||||
|
||||
final VolumeInfo vi = mAudioService.getDeviceVolume(volMin, usbDevice, mPackageName);
|
||||
Assert.assertEquals("getDeviceVolume doesn't return expected value in " + vi
|
||||
+ " after setting " + volMid,
|
||||
(volMid.getMaxVolumeIndex() - volMid.getMinVolumeIndex()) / 2,
|
||||
(vi.getMaxVolumeIndex() - vi.getMinVolumeIndex()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user