From 32a2b5f661a88a9d5cc2b0a46892a673e3c6e6d8 Mon Sep 17 00:00:00 2001 From: Francois Gaffie Date: Wed, 10 Nov 2021 13:45:42 +0100 Subject: [PATCH] [IMPR] AudioManager: add adjustAttributesVolume API Bug: 237409207 Test: make In order to manage mute / unmute from applications, it is required to align volume per attributes on volume per stream regarding the mute management. Test: atest AudioManagerTest#testAdjustVolumeGroupVolume Signed-off-by: Francois Gaffie Change-Id: I3ad42802b8387ecbbb15a54774f4d2da0fed0988 --- core/api/current.txt | 3 + core/api/system-current.txt | 5 + media/java/android/media/AudioManager.java | 198 ++++++++++++++++-- media/java/android/media/IAudioService.aidl | 25 ++- .../android/server/audio/AudioService.java | 190 ++++++++++++----- .../server/audio/AudioServiceEvents.java | 35 ++-- 6 files changed, 368 insertions(+), 88 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 6249b41990867..3824f9c1493c9 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -20911,6 +20911,7 @@ package android.media { method public void adjustStreamVolume(int, int, int); method public void adjustSuggestedStreamVolume(int, int, int); method public void adjustVolume(int, int); + method public void adjustVolumeGroupVolume(int, int, int); method public void clearCommunicationDevice(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS) public boolean clearPreferredMixerAttributes(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioDeviceInfo); method public void dispatchMediaKeyEvent(android.view.KeyEvent); @@ -20941,6 +20942,7 @@ package android.media { method public float getStreamVolumeDb(int, int, int); method @NonNull public java.util.List getSupportedMixerAttributes(@NonNull android.media.AudioDeviceInfo); method @Deprecated public int getVibrateSetting(int); + method public int getVolumeGroupIdForAttributes(@NonNull android.media.AudioAttributes); method @Deprecated public boolean isBluetoothA2dpOn(); method public boolean isBluetoothScoAvailableOffCall(); method @Deprecated public boolean isBluetoothScoOn(); @@ -20954,6 +20956,7 @@ package android.media { method public boolean isStreamMute(int); method public boolean isSurroundFormatEnabled(int); method public boolean isVolumeFixed(); + method public boolean isVolumeGroupMuted(int); method @Deprecated public boolean isWiredHeadsetOn(); method public void loadSoundEffects(); method public void playSoundEffect(int); diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7025b2be3df79..b486297d811b3 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -6672,6 +6672,7 @@ package android.media { method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public int getDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes); method @NonNull @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_ROUTING, "android.permission.QUERY_AUDIO_STATE"}) public java.util.List getDevicesForAttributes(@NonNull android.media.AudioAttributes); method @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleStreamVolume(int); + method @IntRange(from=0) @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public int getLastAudibleVolumeGroupVolume(int); method @IntRange(from=0) public long getMaxAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMaxVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); @@ -6681,6 +6682,9 @@ package android.media { method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List getPreferredDevicesForCapturePreset(int); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public java.util.List getPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy); method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMaxVolumeIndex(int); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupMinVolumeIndex(int); + method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int getVolumeGroupVolumeIndex(int); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isBluetoothVariableLatencyEnabled(); @@ -6714,6 +6718,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDeviceForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull android.media.AudioDeviceAttributes); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); + method @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public void setVolumeGroupVolumeIndex(int, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean supportsBluetoothVariableLatency(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 3fbada77667ad..f7191d82437f7 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -1350,12 +1350,8 @@ public class AudioManager { public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags) { Preconditions.checkNotNull(attr, "attr must not be null"); final IAudioService service = getService(); - try { - service.setVolumeIndexForAttributes(attr, index, flags, - getContext().getOpPackageName(), getContext().getAttributionTag()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + int groupId = getVolumeGroupIdForAttributes(attr); + setVolumeGroupVolumeIndex(groupId, index, flags); } /** @@ -1374,11 +1370,8 @@ public class AudioManager { public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); final IAudioService service = getService(); - try { - return service.getVolumeIndexForAttributes(attr); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + int groupId = getVolumeGroupIdForAttributes(attr); + return getVolumeGroupVolumeIndex(groupId); } /** @@ -1395,11 +1388,8 @@ public class AudioManager { public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); final IAudioService service = getService(); - try { - return service.getMaxVolumeIndexForAttributes(attr); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + int groupId = getVolumeGroupIdForAttributes(attr); + return getVolumeGroupMaxVolumeIndex(groupId); } /** @@ -1415,9 +1405,183 @@ public class AudioManager { @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { Preconditions.checkNotNull(attr, "attr must not be null"); + final IAudioService service = getService(); + int groupId = getVolumeGroupIdForAttributes(attr); + return getVolumeGroupMinVolumeIndex(groupId); + } + + /** + * Returns the volume group id associated to the given {@link AudioAttributes}. + * + * @param attributes The {@link AudioAttributes} to consider. + * @return {@link android.media.audiopolicy.AudioVolumeGroup} id supporting the given + * {@link AudioAttributes} if found, + * {@code android.media.audiopolicy.AudioVolumeGroup.DEFAULT_VOLUME_GROUP} otherwise. + */ + public int getVolumeGroupIdForAttributes(@NonNull AudioAttributes attributes) { + Preconditions.checkNotNull(attributes, "Audio Attributes must not be null"); + return AudioProductStrategy.getVolumeGroupIdForAudioAttributes(attributes, + /* fallbackOnDefault= */ false); + } + + /** + * Sets the volume index for a particular group associated to given id. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} + * to retrieve the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @param index The volume index to set. See + * {@link #getVolumeGroupMaxVolumeIndex(id)} for the largest valid value + * {@link #getVolumeGroupMinVolumeIndex(id)} for the lowest valid value. + * @param flags One or more flags. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public void setVolumeGroupVolumeIndex(int groupId, int index, int flags) { final IAudioService service = getService(); try { - return service.getMinVolumeIndexForAttributes(attr); + service.setVolumeGroupVolumeIndex(groupId, index, flags, + getContext().getOpPackageName(), getContext().getAttributionTag()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current volume index for a particular group associated to given id. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} + * to retrieve the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @return The current volume index for the stream. + * @hide + */ + @SystemApi + @IntRange(from = 0) + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public int getVolumeGroupVolumeIndex(int groupId) { + final IAudioService service = getService(); + try { + return service.getVolumeGroupVolumeIndex(groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the maximum volume index for a particular group associated to given id. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} + * to retrieve the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @return The maximum valid volume index for the {@link AudioAttributes}. + * @hide + */ + @SystemApi + @IntRange(from = 0) + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public int getVolumeGroupMaxVolumeIndex(int groupId) { + final IAudioService service = getService(); + try { + return service.getVolumeGroupMaxVolumeIndex(groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the minimum volume index for a particular group associated to given id. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} + * to retrieve the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @return The minimum valid volume index for the {@link AudioAttributes}. + * @hide + */ + @SystemApi + @IntRange(from = 0) + @RequiresPermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public int getVolumeGroupMinVolumeIndex(int groupId) { + final IAudioService service = getService(); + try { + return service.getVolumeGroupMinVolumeIndex(groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Adjusts the volume of a particular group associated to given id by one step in a direction. + *

If the volume group is associated to a stream type, it fallbacks on + * {@link #adjustStreamVolume(int, int, int)} for compatibility reason. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve + * the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @param direction The direction to adjust the volume. One of + * {@link #ADJUST_LOWER}, {@link #ADJUST_RAISE}, or + * {@link #ADJUST_SAME}. + * @param flags One or more flags. + * @throws SecurityException if the adjustment triggers a Do Not Disturb change and the caller + * is not granted notification policy access. + */ + public void adjustVolumeGroupVolume(int groupId, int direction, int flags) { + IAudioService service = getService(); + try { + service.adjustVolumeGroupVolume(groupId, direction, flags, + getContext().getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Get last audible volume of the group associated to given id before it was muted. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve + * the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @return current volume if not muted, volume before muted otherwise. + * @hide + */ + @SystemApi + @RequiresPermission("android.permission.QUERY_AUDIO_STATE") + @IntRange(from = 0) + public int getLastAudibleVolumeGroupVolume(int groupId) { + IAudioService service = getService(); + try { + return service.getLastAudibleVolumeGroupVolume(groupId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Returns the current mute state for a particular volume group associated to the given id. + *

Call first in prior {@link #getVolumeGroupIdForAttributes(AudioAttributes)} to retrieve + * the volume group id supporting the given {@link AudioAttributes}. + * + * @param groupId of the {@link android.media.audiopolicy.AudioVolumeGroup} to consider. + * @return The mute state for the given {@link android.media.audiopolicy.AudioVolumeGroup} id. + * @see #adjustVolumeGroupVolume(int, int, int) + */ + public boolean isVolumeGroupMuted(int groupId) { + IAudioService service = getService(); + try { + return service.isVolumeGroupMuted(groupId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index c06352c21ee4f..0364e346d2c83 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -138,18 +138,25 @@ interface IAudioService { @EnforcePermission("MODIFY_AUDIO_ROUTING") List getAudioVolumeGroups(); - @EnforcePermission("MODIFY_AUDIO_ROUTING") - void setVolumeIndexForAttributes(in AudioAttributes aa, int index, int flags, - String callingPackage, in String attributionTag); + @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"}) + void setVolumeGroupVolumeIndex(int groupId, int index, int flags, String callingPackage, + in String attributionTag); - @EnforcePermission("MODIFY_AUDIO_ROUTING") - int getVolumeIndexForAttributes(in AudioAttributes aa); + @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"}) + int getVolumeGroupVolumeIndex(int groupId); - @EnforcePermission("MODIFY_AUDIO_ROUTING") - int getMaxVolumeIndexForAttributes(in AudioAttributes aa); + @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"}) + int getVolumeGroupMaxVolumeIndex(int groupId); - @EnforcePermission("MODIFY_AUDIO_ROUTING") - int getMinVolumeIndexForAttributes(in AudioAttributes aa); + @EnforcePermission(anyOf={"MODIFY_AUDIO_SYSTEM_SETTINGS", "MODIFY_AUDIO_ROUTING"}) + int getVolumeGroupMinVolumeIndex(int groupId); + + @EnforcePermission("QUERY_AUDIO_STATE") + int getLastAudibleVolumeGroupVolume(int groupId); + + boolean isVolumeGroupMuted(int groupId); + + void adjustVolumeGroupVolume(int groupId, int direction, int flags, String callingPackage); @EnforcePermission("QUERY_AUDIO_STATE") int getLastAudibleStreamVolume(int streamType); diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index cb98c6653067f..524ac1c436937 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -2613,13 +2613,11 @@ public class AudioService extends IAudioService.Stub } if (!TextUtils.isEmpty(packageName)) { PackageManager pm = mContext.getPackageManager(); - ActivityManager am = - (ActivityManager) mContext.getSystemService(mContext.ACTIVITY_SERVICE); if (pm.checkPermission(Manifest.permission.CAPTURE_AUDIO_HOTWORD, packageName) == PackageManager.PERMISSION_GRANTED) { try { - assistantUid = pm.getPackageUidAsUser(packageName, am.getCurrentUser()); + assistantUid = pm.getPackageUidAsUser(packageName, getCurrentUserId()); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, "updateAssistantUId() could not find UID for package: " + packageName); @@ -3766,23 +3764,23 @@ public class AudioService extends IAudioService.Stub } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - /** @see AudioManager#setVolumeIndexForAttributes(attr, int, int) */ - public void setVolumeIndexForAttributes(@NonNull AudioAttributes attr, int index, int flags, + @Override + @android.annotation.EnforcePermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + /** @see AudioManager#setVolumeGroupVolumeIndex(int, int, int) */ + public void setVolumeGroupVolumeIndex(int groupId, int index, int flags, String callingPackage, String attributionTag) { - super.setVolumeIndexForAttributes_enforcePermission(); - - Objects.requireNonNull(attr, "attr must not be null"); - int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes( - attr, /* fallbackOnDefault= */false); - if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) { - Log.e(TAG, ": no volume group found for attributes " + attr.toString()); + super.setVolumeGroupVolumeIndex_enforcePermission(); + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + Log.e(TAG, ": no volume group found for id " + groupId); return; } - VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup); + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); - sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, attr, vgs.name(), - index, flags, callingPackage + ", user " + ActivityManager.getCurrentUser())); + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_SET_GROUP_VOL, vgs.name(), + index, flags, callingPackage + ", user " + getCurrentUserId())); vgs.setVolumeIndex(index, flags); @@ -3791,7 +3789,7 @@ public class AudioService extends IAudioService.Stub try { ensureValidStreamType(groupedStream); } catch (IllegalArgumentException e) { - Log.d(TAG, "volume group " + volumeGroup + " has internal streams (" + groupedStream + Log.d(TAG, "volume group " + groupId + " has internal streams (" + groupedStream + "), do not change associated stream volume"); continue; } @@ -3813,39 +3811,53 @@ public class AudioService extends IAudioService.Stub return null; } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - /** @see AudioManager#getVolumeIndexForAttributes(attr) */ - public int getVolumeIndexForAttributes(@NonNull AudioAttributes attr) { - super.getVolumeIndexForAttributes_enforcePermission(); - - Objects.requireNonNull(attr, "attr must not be null"); + @Override + @android.annotation.EnforcePermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + /** @see AudioManager#getVolumeGroupVolumeIndex(int) */ + public int getVolumeGroupVolumeIndex(int groupId) { + super.getVolumeGroupVolumeIndex_enforcePermission(); synchronized (VolumeStreamState.class) { - int volumeGroup = AudioProductStrategy.getVolumeGroupIdForAudioAttributes( - attr, /* fallbackOnDefault= */false); - if (sVolumeGroupStates.indexOfKey(volumeGroup) < 0) { - throw new IllegalArgumentException("No volume group for attributes " + attr); + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + throw new IllegalArgumentException("No volume group for id " + groupId); } - VolumeGroupState vgs = sVolumeGroupStates.get(volumeGroup); + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); return vgs.isMuted() ? vgs.getMinIndex() : vgs.getVolumeIndex(); } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - /** @see AudioManager#getMaxVolumeIndexForAttributes(attr) */ - public int getMaxVolumeIndexForAttributes(@NonNull AudioAttributes attr) { - super.getMaxVolumeIndexForAttributes_enforcePermission(); - - Objects.requireNonNull(attr, "attr must not be null"); - return AudioSystem.getMaxVolumeIndexForAttributes(attr); + /** @see AudioManager#getVolumeGroupMaxVolumeIndex(int) */ + @android.annotation.EnforcePermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public int getVolumeGroupMaxVolumeIndex(int groupId) { + super.getVolumeGroupMaxVolumeIndex_enforcePermission(); + synchronized (VolumeStreamState.class) { + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + throw new IllegalArgumentException("No volume group for id " + groupId); + } + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); + return vgs.getMaxIndex(); + } } - @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) - /** @see AudioManager#getMinVolumeIndexForAttributes(attr) */ - public int getMinVolumeIndexForAttributes(@NonNull AudioAttributes attr) { - super.getMinVolumeIndexForAttributes_enforcePermission(); - - Objects.requireNonNull(attr, "attr must not be null"); - return AudioSystem.getMinVolumeIndexForAttributes(attr); + /** @see AudioManager#getVolumeGroupMinVolumeIndex(int) */ + @android.annotation.EnforcePermission(anyOf = { + android.Manifest.permission.MODIFY_AUDIO_SYSTEM_SETTINGS, + android.Manifest.permission.MODIFY_AUDIO_ROUTING + }) + public int getVolumeGroupMinVolumeIndex(int groupId) { + super.getVolumeGroupMinVolumeIndex_enforcePermission(); + synchronized (VolumeStreamState.class) { + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + throw new IllegalArgumentException("No volume group for id " + groupId); + } + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); + return vgs.getMinIndex(); + } } @Override @@ -3914,6 +3926,46 @@ public class AudioService extends IAudioService.Stub callingPackage, /*attributionTag*/ null); } + /** @see AudioManager#adjustVolumeGroupVolume(int, int, int) */ + public void adjustVolumeGroupVolume(int groupId, int direction, int flags, + String callingPackage) { + ensureValidDirection(direction); + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + Log.e(TAG, ": no volume group found for id " + groupId); + return; + } + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); + sVolumeLogger.enqueue(new VolumeEvent(VolumeEvent.VOL_ADJUST_GROUP_VOL, vgs.name(), + direction, flags, callingPackage)); + vgs.adjustVolume(direction, flags); + } + + /** @see AudioManager#getLastAudibleVolumeGroupVolume(int) */ + @android.annotation.EnforcePermission(android.Manifest.permission.QUERY_AUDIO_STATE) + public int getLastAudibleVolumeGroupVolume(int groupId) { + super.getLastAudibleVolumeGroupVolume_enforcePermission(); + synchronized (VolumeStreamState.class) { + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + Log.e(TAG, ": no volume group found for id " + groupId); + return 0; + } + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); + return vgs.getVolumeIndex(); + } + } + + /** @see AudioManager#isVolumeGroupMuted(int) */ + public boolean isVolumeGroupMuted(int groupId) { + synchronized (VolumeStreamState.class) { + if (sVolumeGroupStates.indexOfKey(groupId) < 0) { + Log.e(TAG, ": no volume group found for id " + groupId); + return false; + } + VolumeGroupState vgs = sVolumeGroupStates.get(groupId); + return vgs.isMuted(); + } + } + /** @see AudioManager#setStreamVolume(int, int, int) * Part of service interface, check permissions here */ public void setStreamVolumeWithAttribution(int streamType, int index, int flags, @@ -7489,14 +7541,56 @@ public class AudioService extends IAudioService.Stub return mIsMuted; } + public void adjustVolume(int direction, int flags) { + synchronized (AudioService.VolumeStreamState.class) { + int device = getDeviceForVolume(); + int previousIndex = getIndex(device); + + switch (direction) { + case AudioManager.ADJUST_TOGGLE_MUTE: { + // Note: If muted by volume 0, unmute will restore volume 0. + mute(!mIsMuted); + break; + } + case AudioManager.ADJUST_UNMUTE: + // Note: If muted by volume 0, unmute will restore volume 0. + mute(false); + break; + case AudioManager.ADJUST_MUTE: + // May be already muted by setvolume 0, prevent from setting same value + if (previousIndex != 0) { + // bypass persist + mute(true); + } + mIsMuted = true; + break; + case AudioManager.ADJUST_RAISE: + // As for stream, RAISE during mute will increment the index + setVolumeIndex(Math.min(previousIndex + 1, mIndexMax), device, flags); + break; + case AudioManager.ADJUST_LOWER: + // For stream, ADJUST_LOWER on a muted VSS is a no-op + // If we decide to unmute on ADJUST_LOWER, cannot fallback on + // adjustStreamVolume for group associated to legacy stream type + if (isMuted() && previousIndex != 0) { + mute(false); + } else { + int newIndex = Math.max(previousIndex - 1, mIndexMin); + setVolumeIndex(newIndex, device, flags); + } + break; + } + } + } + public int getVolumeIndex() { - synchronized (VolumeStreamState.class) { + synchronized (AudioService.VolumeStreamState.class) { return getIndex(getDeviceForVolume()); } } public void setVolumeIndex(int index, int flags) { - synchronized (VolumeStreamState.class) { + synchronized (AudioService.VolumeStreamState.class) { if (mUseFixedVolume) { return; } @@ -7581,7 +7675,7 @@ public class AudioService extends IAudioService.Stub public void applyAllVolumes(boolean userSwitch) { String caller = "from vgs"; - synchronized (VolumeStreamState.class) { + synchronized (AudioService.VolumeStreamState.class) { // apply device specific volumes first for (int i = 0; i < mIndexMap.size(); i++) { int device = mIndexMap.keyAt(i); @@ -7681,7 +7775,7 @@ public class AudioService extends IAudioService.Stub Log.v(TAG, "persistVolumeGroup: storing index " + getIndex(device) + " for group " + mAudioVolumeGroup.name() + ", device " + AudioSystem.getOutputDeviceName(device) - + " and User=" + ActivityManager.getCurrentUser()); + + " and User=" + getCurrentUserId()); } boolean success = mSettings.putSystemIntForUser(mContentResolver, getSettingNameForDevice(device), @@ -7693,7 +7787,7 @@ public class AudioService extends IAudioService.Stub } public void readSettings() { - synchronized (VolumeStreamState.class) { + synchronized (AudioService.VolumeStreamState.class) { // force maximum volume on all streams if fixed volume property is set if (mUseFixedVolume) { mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax); @@ -7720,7 +7814,7 @@ public class AudioService extends IAudioService.Stub if (DEBUG_VOL) { Log.v(TAG, "readSettings: found stored index " + getValidIndex(index) + " for group " + mAudioVolumeGroup.name() + ", device: " + name - + ", User=" + ActivityManager.getCurrentUser()); + + ", User=" + getCurrentUserId()); } mIndexMap.put(device, getValidIndex(index)); } diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java index d30bec70ce9e8..58caf5ae8ca07 100644 --- a/services/core/java/com/android/server/audio/AudioServiceEvents.java +++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java @@ -17,7 +17,6 @@ package com.android.server.audio; import android.annotation.NonNull; -import android.media.AudioAttributes; import android.media.AudioDeviceAttributes; import android.media.AudioManager; import android.media.AudioSystem; @@ -197,6 +196,7 @@ public class AudioServiceEvents { static final int VOL_SET_GROUP_VOL = 8; static final int VOL_MUTE_STREAM_INT = 9; static final int VOL_SET_LE_AUDIO_VOL = 10; + static final int VOL_ADJUST_GROUP_VOL = 11; final int mOp; final int mStream; @@ -204,7 +204,6 @@ public class AudioServiceEvents { final int mVal2; final String mCaller; final String mGroupName; - final AudioAttributes mAudioAttributes; /** used for VOL_ADJUST_VOL_UID, * VOL_ADJUST_SUGG_VOL, @@ -217,7 +216,6 @@ public class AudioServiceEvents { mVal2 = val2; mCaller = caller; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } @@ -230,7 +228,6 @@ public class AudioServiceEvents { mStream = -1; mCaller = null; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } @@ -243,7 +240,6 @@ public class AudioServiceEvents { mStream = -1; mCaller = null; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } @@ -256,7 +252,6 @@ public class AudioServiceEvents { // unused mCaller = null; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } @@ -269,19 +264,18 @@ public class AudioServiceEvents { // unused mCaller = null; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } - /** used for VOL_SET_GROUP_VOL */ - VolumeEvent(int op, AudioAttributes aa, String group, int index, int flags, String caller) { + /** used for VOL_SET_GROUP_VOL, + * VOL_ADJUST_GROUP_VOL */ + VolumeEvent(int op, String group, int index, int flags, String caller) { mOp = op; mStream = -1; mVal1 = index; mVal2 = flags; mCaller = caller; mGroupName = group; - mAudioAttributes = aa; logMetricEvent(); } @@ -293,7 +287,6 @@ public class AudioServiceEvents { mVal2 = 0; mCaller = null; mGroupName = null; - mAudioAttributes = null; logMetricEvent(); } @@ -335,6 +328,15 @@ public class AudioServiceEvents { .record(); return; } + case VOL_ADJUST_GROUP_VOL: + new MediaMetrics.Item(mMetricsId) + .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller) + .set(MediaMetrics.Property.DIRECTION, mVal1 > 0 ? "up" : "down") + .set(MediaMetrics.Property.EVENT, "adjustVolumeGroupVolume") + .set(MediaMetrics.Property.FLAGS, mVal2) + .set(MediaMetrics.Property.GROUP, mGroupName) + .record(); + return; case VOL_SET_STREAM_VOL: new MediaMetrics.Item(mMetricsId) .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller) @@ -386,7 +388,6 @@ public class AudioServiceEvents { return; case VOL_SET_GROUP_VOL: new MediaMetrics.Item(mMetricsId) - .set(MediaMetrics.Property.ATTRIBUTES, mAudioAttributes.toString()) .set(MediaMetrics.Property.CALLING_PACKAGE, mCaller) .set(MediaMetrics.Property.EVENT, "setVolumeIndexForAttributes") .set(MediaMetrics.Property.FLAGS, mVal2) @@ -412,6 +413,13 @@ public class AudioServiceEvents { .append(" flags:0x").append(Integer.toHexString(mVal2)) .append(") from ").append(mCaller) .toString(); + case VOL_ADJUST_GROUP_VOL: + return new StringBuilder("adjustVolumeGroupVolume(group:") + .append(mGroupName) + .append(" dir:").append(AudioManager.adjustToString(mVal1)) + .append(" flags:0x").append(Integer.toHexString(mVal2)) + .append(") from ").append(mCaller) + .toString(); case VOL_ADJUST_STREAM_VOL: return new StringBuilder("adjustStreamVolume(stream:") .append(AudioSystem.streamToString(mStream)) @@ -460,8 +468,7 @@ public class AudioServiceEvents { .append(" stream:").append(AudioSystem.streamToString(mStream)) .toString(); case VOL_SET_GROUP_VOL: - return new StringBuilder("setVolumeIndexForAttributes(attr:") - .append(mAudioAttributes.toString()) + return new StringBuilder("setVolumeIndexForAttributes(group:") .append(" group: ").append(mGroupName) .append(" index:").append(mVal1) .append(" flags:0x").append(Integer.toHexString(mVal2))