Loading media/java/android/media/AudioDeviceAttributes.java +14 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,20 @@ public final class AudioDeviceAttributes implements Parcelable { + " descriptors:" + mAudioDescriptors.toString()); } /** * @hide * Creates a copy of an AudioDeviceAttributes that only stores the device type, role and * address. * * <p>It's recommended to use this method when comparing instances with equals (e.g.: when * using them as keys to maps) to recognize a given device based on type and address, * ignoring any other fields such as audio descriptors and profiles. * @return a new AudioDeviceAttributes from type and address of the original one */ public AudioDeviceAttributes createFromTypeAndAddress() { return new AudioDeviceAttributes(mNativeType, mAddress); } @Override public int describeContents() { return 0; Loading services/core/java/com/android/server/audio/AudioService.java +107 −49 Original line number Diff line number Diff line Loading @@ -936,7 +936,8 @@ public class AudioService extends IAudioService.Stub // For possible volume behaviors, see // {@link AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior}. @GuardedBy("mAbsoluteVolumeDeviceInfoMapLock") Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>(); Map<AudioDeviceAttributes, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>(); /** * Stores information about a device using absolute volume behavior. Loading Loading @@ -992,8 +993,7 @@ public class AudioService extends IAudioService.Stub @Override public void binderDied() { if (mParent.removeAudioSystemDeviceOutFromAbsVolumeDevices(mDevice.getInternalType()) != null) { if (mParent.removeFromAbsoluteVolumeDevices(mDevice) != null) { mParent.dispatchDeviceVolumeBehavior(mDevice, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); } Loading Loading @@ -4184,9 +4184,15 @@ public class AudioService extends IAudioService.Stub int oldIndex = getVssForStreamOrDefault(streamType).getIndex(deviceType); // Check if the volume adjustment should be handled by an absolute volume controller instead if (isAbsoluteVolumeDevice(deviceType) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(deviceType); boolean isAbsoluteVolumeDevice = unifyAbsoluteVolumeManagement() ? isAbsoluteVolumeDevice( deviceAttr) : isAbsoluteVolumeDevice(deviceType); if (isAbsoluteVolumeDevice && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info; if (unifyAbsoluteVolumeManagement()) { info = getAbsoluteVolumeDeviceInfo(deviceAttr); } else { info = getAbsoluteVolumeDeviceInfo(deviceType); } if (info != null && info.mHandlesVolumeAdjustment) { dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction, keyEventMode); Loading Loading @@ -4314,14 +4320,20 @@ public class AudioService extends IAudioService.Stub } private boolean handleAbsoluteVolume(int streamType, int streamTypeAlias, AudioDeviceAttributes deviceAttr, int newIndex, int flags) { @NonNull AudioDeviceAttributes ada, int newIndex, int flags) { // Check if volume update should be handled by an external volume controller boolean registeredAsAbsoluteVolume = false; boolean volumeHandled = false; int deviceType = deviceAttr.getInternalType(); if (isAbsoluteVolumeDevice(deviceType) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(deviceType); int deviceType = ada.getInternalType(); boolean isAbsoluteVolume = unifyAbsoluteVolumeManagement() ? isAbsoluteVolumeDevice(ada) : isAbsoluteVolumeDevice(deviceType); if (isAbsoluteVolume && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info; if (unifyAbsoluteVolumeManagement()) { info = getAbsoluteVolumeDeviceInfo(ada); } else { info = getAbsoluteVolumeDeviceInfo(deviceType); } if (info != null) { dispatchAbsoluteVolumeChanged(streamType, info, newIndex); registeredAsAbsoluteVolume = true; Loading Loading @@ -4700,7 +4712,8 @@ public class AudioService extends IAudioService.Stub final AudioDeviceAttributes currDevAttr = getDeviceAttributesForStream(streamType); final boolean skipping = (currDevAttr.getInternalType() == ada.getInternalType()) || (vss == null); (unifyAbsoluteVolumeManagement() ? currDevAttr.equalTypeAddress(ada) : currDevAttr.getInternalType() == ada.getInternalType()) || (vss == null); AudioService.sVolumeLogger.enqueue(new DeviceVolumeEvent(streamType, index, ada, currDevAttr.getInternalType(), callingPackage, skipping)); Loading Loading @@ -5243,8 +5256,7 @@ public class AudioService extends IAudioService.Stub if (absVolumeDevices.size() > 1) { Slog.w(TAG, "onUpdateContextualVolumes too many active devices: " + absVolumeDevices.stream().map(AudioDeviceAttributes::toString) .collect(Collectors.joining(",")) + ", for stream: " + streamType); .collect(Collectors.joining(",")) + ", for stream: " + streamType); return; } Loading Loading @@ -8324,8 +8336,13 @@ public class AudioService extends IAudioService.Stub if (register) { AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo(this, device, volumes, cb, handlesVolumeAdjustment, deviceVolumeBehavior); final AbsoluteVolumeDeviceInfo oldInfo = getAbsoluteVolumeDeviceInfo(deviceOut); addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info); AbsoluteVolumeDeviceInfo oldInfo; if (unifyAbsoluteVolumeManagement()) { oldInfo = getAbsoluteVolumeDeviceInfo(device); } else { oldInfo = getAbsoluteVolumeDeviceInfo(deviceOut); } addToAbsoluteVolumeDevices(device, info); boolean volumeBehaviorChanged = (oldInfo == null) || (oldInfo.mDeviceVolumeBehavior != deviceVolumeBehavior); Loading Loading @@ -8357,8 +8374,7 @@ public class AudioService extends IAudioService.Stub } } } else { AbsoluteVolumeDeviceInfo deviceInfo = removeAudioSystemDeviceOutFromAbsVolumeDevices( deviceOut); AbsoluteVolumeDeviceInfo deviceInfo = removeFromAbsoluteVolumeDevices(device); if (deviceInfo != null) { deviceInfo.unlinkToDeath(); dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); Loading Loading @@ -8398,10 +8414,15 @@ public class AudioService extends IAudioService.Stub return; } setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName); // sanitize the device to contain only type and address final AudioDeviceAttributes sanitizedDevice = new AudioDeviceAttributes( device.getInternalType(), device.getAddress()); setDeviceVolumeBehaviorInternal(sanitizedDevice, deviceVolumeBehavior, pkgName); persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior); } @SuppressLint("ShortCircuitBoolean") // we need to execute all or statements private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device, @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) { Loading @@ -8413,22 +8434,19 @@ public class AudioService extends IAudioService.Stub volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED: volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL: volumeBehaviorChanged |= addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut) | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY: Loading Loading @@ -8489,17 +8507,15 @@ public class AudioService extends IAudioService.Stub if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; } // sanitize the device to contain only type and address final AudioDeviceAttributes sanitizedDevice = device.createFromTypeAndAddress(); synchronized (mAbsoluteVolumeDeviceInfoMapLock) { if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) { final AbsoluteVolumeDeviceInfo deviceInfo = mAbsoluteVolumeDeviceInfoMap.get( audioSystemDeviceOut); sanitizedDevice); if (deviceInfo != null) { return deviceInfo.mDeviceVolumeBehavior; } Log.e(TAG, "Null absolute volume device info stored for key " + audioSystemDeviceOut); } } if (isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut) Loading Loading @@ -12920,7 +12936,7 @@ public class AudioService extends IAudioService.Stub synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.entrySet().stream() .filter(entry -> entry.getValue().mDeviceVolumeBehavior == behavior) .map(Map.Entry::getKey) .map(entry -> entry.getKey().getInternalType()) .collect(Collectors.toSet()); } } Loading Loading @@ -15521,7 +15537,25 @@ public class AudioService extends IAudioService.Stub @Nullable private AbsoluteVolumeDeviceInfo getAbsoluteVolumeDeviceInfo(int deviceType) { synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.get(deviceType); Optional<AbsoluteVolumeDeviceInfo> info = mAbsoluteVolumeDeviceInfoMap.entrySet().stream().filter( entry -> entry.getKey().getInternalType() == deviceType).map( Map.Entry::getValue).findFirst(); return info.orElse(null); } } /** * Returns the input device which uses absolute volume behavior, including its variants, * or {@code null} if there is no mapping for the AudioDeviceAttributes. * * @param device the simplified attributes continaing onlye address and type */ @Nullable private AbsoluteVolumeDeviceInfo getAbsoluteVolumeDeviceInfo(AudioDeviceAttributes device) { final AudioDeviceAttributes ada = device.createFromTypeAndAddress(); synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.get(ada); } } Loading @@ -15535,7 +15569,8 @@ public class AudioService extends IAudioService.Stub private boolean isAbsoluteVolumeDevice(int deviceType) { boolean hasAbsoluteVolumeDeviceKey; synchronized (mAbsoluteVolumeDeviceInfoMapLock) { hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType); hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.entrySet().stream().anyMatch( entry -> entry.getKey().getInternalType() == deviceType); } if (unifyAbsoluteVolumeManagement() && hasAbsoluteVolumeDeviceKey) { return true; Loading @@ -15548,6 +15583,27 @@ public class AudioService extends IAudioService.Stub } } /** * Returns whether the input device uses absolute volume behavior, including its variants. * For included volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}. */ private boolean isAbsoluteVolumeDevice(AudioDeviceAttributes ada) { boolean hasAbsoluteVolumeDeviceKey; synchronized (mAbsoluteVolumeDeviceInfoMapLock) { hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.containsKey( ada.createFromTypeAndAddress()); } if (unifyAbsoluteVolumeManagement() && hasAbsoluteVolumeDeviceKey) { return true; } else { return hasAbsoluteVolumeDeviceKey || isA2dpAbsoluteVolumeDevice(ada.getInternalType()) || AudioSystem.isLeAudioDeviceType(ada.getInternalType()) || ada.getInternalType() == AudioSystem.DEVICE_OUT_HEARING_AID || ada.getInternalType() == AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; } } /** * Returns whether the input device is a Bluetooth A2dp device that uses absolute volume * behavior. This is distinct from the general implementation of absolute volume behavior Loading @@ -15559,7 +15615,8 @@ public class AudioService extends IAudioService.Stub private boolean isHdmiAbsoluteVolumeDevice(int deviceType) { synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType) return mAbsoluteVolumeDeviceInfoMap.entrySet().stream().anyMatch( entry -> entry.getKey().getInternalType() == deviceType) && (deviceType == AudioSystem.DEVICE_OUT_HDMI || deviceType == AudioSystem.DEVICE_OUT_HDMI_ARC || deviceType == AudioSystem.DEVICE_OUT_HDMI_EARC); Loading Loading @@ -15658,33 +15715,34 @@ public class AudioService extends IAudioService.Stub return mFullVolumeDevices.remove(audioSystemDeviceOut); } private void addAudioSystemDeviceOutToAbsVolumeDevices(int audioSystemDeviceOut, private void addToAbsoluteVolumeDevices(AudioDeviceAttributes ada, AbsoluteVolumeDeviceInfo info) { if (info == null) { Log.e(TAG, "Cannot add null absolute volume info for audioSystemDeviceOut " + audioSystemDeviceOut); Log.e(TAG, "Cannot add null absolute volume info for ada " + ada); return; } final AudioDeviceAttributes adaAsKey = ada.createFromTypeAndAddress(); if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) Log.d(TAG, "Adding device: " + adaAsKey + " to mAbsoluteVolumeDeviceInfoMap with behavior " + AudioDeviceVolumeManager.volumeBehaviorName(info.mDeviceVolumeBehavior) ); } synchronized (mAbsoluteVolumeDeviceInfoMapLock) { mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info); mAbsoluteVolumeDeviceInfoMap.put(adaAsKey, info); } } private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices( int audioSystemDeviceOut) { private AbsoluteVolumeDeviceInfo removeFromAbsoluteVolumeDevices( AudioDeviceAttributes ada) { final AudioDeviceAttributes deviceOut = ada.createFromTypeAndAddress(); if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mAbsoluteVolumeDeviceInfoMap"); Log.d(TAG, "Removing device: " + deviceOut + " from mAbsoluteVolumeDeviceInfoMap"); } synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut); return mAbsoluteVolumeDeviceInfoMap.remove(deviceOut); } } Loading
media/java/android/media/AudioDeviceAttributes.java +14 −0 Original line number Diff line number Diff line Loading @@ -331,6 +331,20 @@ public final class AudioDeviceAttributes implements Parcelable { + " descriptors:" + mAudioDescriptors.toString()); } /** * @hide * Creates a copy of an AudioDeviceAttributes that only stores the device type, role and * address. * * <p>It's recommended to use this method when comparing instances with equals (e.g.: when * using them as keys to maps) to recognize a given device based on type and address, * ignoring any other fields such as audio descriptors and profiles. * @return a new AudioDeviceAttributes from type and address of the original one */ public AudioDeviceAttributes createFromTypeAndAddress() { return new AudioDeviceAttributes(mNativeType, mAddress); } @Override public int describeContents() { return 0; Loading
services/core/java/com/android/server/audio/AudioService.java +107 −49 Original line number Diff line number Diff line Loading @@ -936,7 +936,8 @@ public class AudioService extends IAudioService.Stub // For possible volume behaviors, see // {@link AudioDeviceVolumeManager.AbsoluteDeviceVolumeBehavior}. @GuardedBy("mAbsoluteVolumeDeviceInfoMapLock") Map<Integer, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>(); Map<AudioDeviceAttributes, AbsoluteVolumeDeviceInfo> mAbsoluteVolumeDeviceInfoMap = new ArrayMap<>(); /** * Stores information about a device using absolute volume behavior. Loading Loading @@ -992,8 +993,7 @@ public class AudioService extends IAudioService.Stub @Override public void binderDied() { if (mParent.removeAudioSystemDeviceOutFromAbsVolumeDevices(mDevice.getInternalType()) != null) { if (mParent.removeFromAbsoluteVolumeDevices(mDevice) != null) { mParent.dispatchDeviceVolumeBehavior(mDevice, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); } Loading Loading @@ -4184,9 +4184,15 @@ public class AudioService extends IAudioService.Stub int oldIndex = getVssForStreamOrDefault(streamType).getIndex(deviceType); // Check if the volume adjustment should be handled by an absolute volume controller instead if (isAbsoluteVolumeDevice(deviceType) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(deviceType); boolean isAbsoluteVolumeDevice = unifyAbsoluteVolumeManagement() ? isAbsoluteVolumeDevice( deviceAttr) : isAbsoluteVolumeDevice(deviceType); if (isAbsoluteVolumeDevice && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info; if (unifyAbsoluteVolumeManagement()) { info = getAbsoluteVolumeDeviceInfo(deviceAttr); } else { info = getAbsoluteVolumeDeviceInfo(deviceType); } if (info != null && info.mHandlesVolumeAdjustment) { dispatchAbsoluteVolumeAdjusted(streamType, info, oldIndex, direction, keyEventMode); Loading Loading @@ -4314,14 +4320,20 @@ public class AudioService extends IAudioService.Stub } private boolean handleAbsoluteVolume(int streamType, int streamTypeAlias, AudioDeviceAttributes deviceAttr, int newIndex, int flags) { @NonNull AudioDeviceAttributes ada, int newIndex, int flags) { // Check if volume update should be handled by an external volume controller boolean registeredAsAbsoluteVolume = false; boolean volumeHandled = false; int deviceType = deviceAttr.getInternalType(); if (isAbsoluteVolumeDevice(deviceType) && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info = getAbsoluteVolumeDeviceInfo(deviceType); int deviceType = ada.getInternalType(); boolean isAbsoluteVolume = unifyAbsoluteVolumeManagement() ? isAbsoluteVolumeDevice(ada) : isAbsoluteVolumeDevice(deviceType); if (isAbsoluteVolume && (flags & AudioManager.FLAG_ABSOLUTE_VOLUME) == 0) { final AbsoluteVolumeDeviceInfo info; if (unifyAbsoluteVolumeManagement()) { info = getAbsoluteVolumeDeviceInfo(ada); } else { info = getAbsoluteVolumeDeviceInfo(deviceType); } if (info != null) { dispatchAbsoluteVolumeChanged(streamType, info, newIndex); registeredAsAbsoluteVolume = true; Loading Loading @@ -4700,7 +4712,8 @@ public class AudioService extends IAudioService.Stub final AudioDeviceAttributes currDevAttr = getDeviceAttributesForStream(streamType); final boolean skipping = (currDevAttr.getInternalType() == ada.getInternalType()) || (vss == null); (unifyAbsoluteVolumeManagement() ? currDevAttr.equalTypeAddress(ada) : currDevAttr.getInternalType() == ada.getInternalType()) || (vss == null); AudioService.sVolumeLogger.enqueue(new DeviceVolumeEvent(streamType, index, ada, currDevAttr.getInternalType(), callingPackage, skipping)); Loading Loading @@ -5243,8 +5256,7 @@ public class AudioService extends IAudioService.Stub if (absVolumeDevices.size() > 1) { Slog.w(TAG, "onUpdateContextualVolumes too many active devices: " + absVolumeDevices.stream().map(AudioDeviceAttributes::toString) .collect(Collectors.joining(",")) + ", for stream: " + streamType); .collect(Collectors.joining(",")) + ", for stream: " + streamType); return; } Loading Loading @@ -8324,8 +8336,13 @@ public class AudioService extends IAudioService.Stub if (register) { AbsoluteVolumeDeviceInfo info = new AbsoluteVolumeDeviceInfo(this, device, volumes, cb, handlesVolumeAdjustment, deviceVolumeBehavior); final AbsoluteVolumeDeviceInfo oldInfo = getAbsoluteVolumeDeviceInfo(deviceOut); addAudioSystemDeviceOutToAbsVolumeDevices(deviceOut, info); AbsoluteVolumeDeviceInfo oldInfo; if (unifyAbsoluteVolumeManagement()) { oldInfo = getAbsoluteVolumeDeviceInfo(device); } else { oldInfo = getAbsoluteVolumeDeviceInfo(deviceOut); } addToAbsoluteVolumeDevices(device, info); boolean volumeBehaviorChanged = (oldInfo == null) || (oldInfo.mDeviceVolumeBehavior != deviceVolumeBehavior); Loading Loading @@ -8357,8 +8374,7 @@ public class AudioService extends IAudioService.Stub } } } else { AbsoluteVolumeDeviceInfo deviceInfo = removeAudioSystemDeviceOutFromAbsVolumeDevices( deviceOut); AbsoluteVolumeDeviceInfo deviceInfo = removeFromAbsoluteVolumeDevices(device); if (deviceInfo != null) { deviceInfo.unlinkToDeath(); dispatchDeviceVolumeBehavior(device, AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE); Loading Loading @@ -8398,10 +8414,15 @@ public class AudioService extends IAudioService.Stub return; } setDeviceVolumeBehaviorInternal(device, deviceVolumeBehavior, pkgName); // sanitize the device to contain only type and address final AudioDeviceAttributes sanitizedDevice = new AudioDeviceAttributes( device.getInternalType(), device.getAddress()); setDeviceVolumeBehaviorInternal(sanitizedDevice, deviceVolumeBehavior, pkgName); persistDeviceVolumeBehavior(device.getInternalType(), deviceVolumeBehavior); } @SuppressLint("ShortCircuitBoolean") // we need to execute all or statements private void setDeviceVolumeBehaviorInternal(@NonNull AudioDeviceAttributes device, @AudioDeviceVolumeManager.DeviceVolumeBehavior int deviceVolumeBehavior, @NonNull String caller) { Loading @@ -8413,22 +8434,19 @@ public class AudioService extends IAudioService.Stub volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FIXED: volumeBehaviorChanged |= removeAudioSystemDeviceOutFromFullVolumeDevices(audioSystemDeviceOut) | addAudioSystemDeviceOutToFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_FULL: volumeBehaviorChanged |= addAudioSystemDeviceOutToFullVolumeDevices(audioSystemDeviceOut) | removeAudioSystemDeviceOutFromFixedVolumeDevices(audioSystemDeviceOut) | (removeAudioSystemDeviceOutFromAbsVolumeDevices(audioSystemDeviceOut) != null); | (removeFromAbsoluteVolumeDevices(device) != null); break; case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE: case AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_ADJUST_ONLY: Loading Loading @@ -8489,17 +8507,15 @@ public class AudioService extends IAudioService.Stub if (mAbsVolumeMultiModeCaseDevices.contains(audioSystemDeviceOut)) { return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE; } // sanitize the device to contain only type and address final AudioDeviceAttributes sanitizedDevice = device.createFromTypeAndAddress(); synchronized (mAbsoluteVolumeDeviceInfoMapLock) { if (mAbsoluteVolumeDeviceInfoMap.containsKey(audioSystemDeviceOut)) { final AbsoluteVolumeDeviceInfo deviceInfo = mAbsoluteVolumeDeviceInfoMap.get( audioSystemDeviceOut); sanitizedDevice); if (deviceInfo != null) { return deviceInfo.mDeviceVolumeBehavior; } Log.e(TAG, "Null absolute volume device info stored for key " + audioSystemDeviceOut); } } if (isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut) Loading Loading @@ -12920,7 +12936,7 @@ public class AudioService extends IAudioService.Stub synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.entrySet().stream() .filter(entry -> entry.getValue().mDeviceVolumeBehavior == behavior) .map(Map.Entry::getKey) .map(entry -> entry.getKey().getInternalType()) .collect(Collectors.toSet()); } } Loading Loading @@ -15521,7 +15537,25 @@ public class AudioService extends IAudioService.Stub @Nullable private AbsoluteVolumeDeviceInfo getAbsoluteVolumeDeviceInfo(int deviceType) { synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.get(deviceType); Optional<AbsoluteVolumeDeviceInfo> info = mAbsoluteVolumeDeviceInfoMap.entrySet().stream().filter( entry -> entry.getKey().getInternalType() == deviceType).map( Map.Entry::getValue).findFirst(); return info.orElse(null); } } /** * Returns the input device which uses absolute volume behavior, including its variants, * or {@code null} if there is no mapping for the AudioDeviceAttributes. * * @param device the simplified attributes continaing onlye address and type */ @Nullable private AbsoluteVolumeDeviceInfo getAbsoluteVolumeDeviceInfo(AudioDeviceAttributes device) { final AudioDeviceAttributes ada = device.createFromTypeAndAddress(); synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.get(ada); } } Loading @@ -15535,7 +15569,8 @@ public class AudioService extends IAudioService.Stub private boolean isAbsoluteVolumeDevice(int deviceType) { boolean hasAbsoluteVolumeDeviceKey; synchronized (mAbsoluteVolumeDeviceInfoMapLock) { hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType); hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.entrySet().stream().anyMatch( entry -> entry.getKey().getInternalType() == deviceType); } if (unifyAbsoluteVolumeManagement() && hasAbsoluteVolumeDeviceKey) { return true; Loading @@ -15548,6 +15583,27 @@ public class AudioService extends IAudioService.Stub } } /** * Returns whether the input device uses absolute volume behavior, including its variants. * For included volume behaviors, see {@link AudioManager.AbsoluteDeviceVolumeBehavior}. */ private boolean isAbsoluteVolumeDevice(AudioDeviceAttributes ada) { boolean hasAbsoluteVolumeDeviceKey; synchronized (mAbsoluteVolumeDeviceInfoMapLock) { hasAbsoluteVolumeDeviceKey = mAbsoluteVolumeDeviceInfoMap.containsKey( ada.createFromTypeAndAddress()); } if (unifyAbsoluteVolumeManagement() && hasAbsoluteVolumeDeviceKey) { return true; } else { return hasAbsoluteVolumeDeviceKey || isA2dpAbsoluteVolumeDevice(ada.getInternalType()) || AudioSystem.isLeAudioDeviceType(ada.getInternalType()) || ada.getInternalType() == AudioSystem.DEVICE_OUT_HEARING_AID || ada.getInternalType() == AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; } } /** * Returns whether the input device is a Bluetooth A2dp device that uses absolute volume * behavior. This is distinct from the general implementation of absolute volume behavior Loading @@ -15559,7 +15615,8 @@ public class AudioService extends IAudioService.Stub private boolean isHdmiAbsoluteVolumeDevice(int deviceType) { synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.containsKey(deviceType) return mAbsoluteVolumeDeviceInfoMap.entrySet().stream().anyMatch( entry -> entry.getKey().getInternalType() == deviceType) && (deviceType == AudioSystem.DEVICE_OUT_HDMI || deviceType == AudioSystem.DEVICE_OUT_HDMI_ARC || deviceType == AudioSystem.DEVICE_OUT_HDMI_EARC); Loading Loading @@ -15658,33 +15715,34 @@ public class AudioService extends IAudioService.Stub return mFullVolumeDevices.remove(audioSystemDeviceOut); } private void addAudioSystemDeviceOutToAbsVolumeDevices(int audioSystemDeviceOut, private void addToAbsoluteVolumeDevices(AudioDeviceAttributes ada, AbsoluteVolumeDeviceInfo info) { if (info == null) { Log.e(TAG, "Cannot add null absolute volume info for audioSystemDeviceOut " + audioSystemDeviceOut); Log.e(TAG, "Cannot add null absolute volume info for ada " + ada); return; } final AudioDeviceAttributes adaAsKey = ada.createFromTypeAndAddress(); if (DEBUG_VOL) { Log.d(TAG, "Adding DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) Log.d(TAG, "Adding device: " + adaAsKey + " to mAbsoluteVolumeDeviceInfoMap with behavior " + AudioDeviceVolumeManager.volumeBehaviorName(info.mDeviceVolumeBehavior) ); } synchronized (mAbsoluteVolumeDeviceInfoMapLock) { mAbsoluteVolumeDeviceInfoMap.put(audioSystemDeviceOut, info); mAbsoluteVolumeDeviceInfoMap.put(adaAsKey, info); } } private AbsoluteVolumeDeviceInfo removeAudioSystemDeviceOutFromAbsVolumeDevices( int audioSystemDeviceOut) { private AbsoluteVolumeDeviceInfo removeFromAbsoluteVolumeDevices( AudioDeviceAttributes ada) { final AudioDeviceAttributes deviceOut = ada.createFromTypeAndAddress(); if (DEBUG_VOL) { Log.d(TAG, "Removing DeviceType: 0x" + Integer.toHexString(audioSystemDeviceOut) + " from mAbsoluteVolumeDeviceInfoMap"); Log.d(TAG, "Removing device: " + deviceOut + " from mAbsoluteVolumeDeviceInfoMap"); } synchronized (mAbsoluteVolumeDeviceInfoMapLock) { return mAbsoluteVolumeDeviceInfoMap.remove(audioSystemDeviceOut); return mAbsoluteVolumeDeviceInfoMap.remove(deviceOut); } }