AudioService: fix communication device APIs
make sure getAvailableCommunicationDevices() and getCommunicationDevice() always return null or a valid communication device, Bug: 265613261 Bug: 266067856 Test: atest AudioCommunicationDeviceTest Change-Id: I1fc0bc8a372d49b0fb6c8b25fd51fbcf321bab6f Merged-In: I1fc0bc8a372d49b0fb6c8b25fd51fbcf321bab6f
This commit is contained in:
@@ -56,6 +56,7 @@ import android.util.PrintWriterPrinter;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
@@ -434,6 +435,48 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
return device;
|
||||
}
|
||||
|
||||
private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
|
||||
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADSET,
|
||||
AudioDeviceInfo.TYPE_USB_HEADSET,
|
||||
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
|
||||
AudioDeviceInfo.TYPE_HEARING_AID,
|
||||
AudioDeviceInfo.TYPE_BLE_HEADSET,
|
||||
AudioDeviceInfo.TYPE_USB_DEVICE,
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER,
|
||||
AudioDeviceInfo.TYPE_LINE_ANALOG,
|
||||
AudioDeviceInfo.TYPE_HDMI,
|
||||
AudioDeviceInfo.TYPE_AUX_LINE
|
||||
};
|
||||
|
||||
/*package */ static boolean isValidCommunicationDevice(AudioDeviceInfo device) {
|
||||
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
|
||||
if (device.getType() == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* package */ static List<AudioDeviceInfo> getAvailableCommunicationDevices() {
|
||||
ArrayList<AudioDeviceInfo> commDevices = new ArrayList<>();
|
||||
AudioDeviceInfo[] allDevices =
|
||||
AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
|
||||
for (AudioDeviceInfo device : allDevices) {
|
||||
if (isValidCommunicationDevice(device)) {
|
||||
commDevices.add(device);
|
||||
}
|
||||
}
|
||||
return commDevices;
|
||||
}
|
||||
|
||||
private @Nullable AudioDeviceInfo getCommunicationDeviceOfType(int type) {
|
||||
return getAvailableCommunicationDevices().stream().filter(d -> d.getType() == type)
|
||||
.findFirst().orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the device currently requested for communication use case.
|
||||
* @return AudioDeviceInfo the requested device for communication.
|
||||
@@ -441,7 +484,29 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
/* package */ AudioDeviceInfo getCommunicationDevice() {
|
||||
synchronized (mDeviceStateLock) {
|
||||
updateActiveCommunicationDevice();
|
||||
return mActiveCommunicationDevice;
|
||||
AudioDeviceInfo device = mActiveCommunicationDevice;
|
||||
// make sure we return a valid communication device (i.e. a device that is allowed by
|
||||
// setCommunicationDevice()) for consistency.
|
||||
if (device != null) {
|
||||
// a digital dock is used instead of the speaker in speakerphone mode and should
|
||||
// be reflected as such
|
||||
if (device.getType() == AudioDeviceInfo.TYPE_DOCK) {
|
||||
device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_SPEAKER);
|
||||
}
|
||||
}
|
||||
// Try to default to earpiece when current communication device is not valid. This can
|
||||
// happen for instance if no call is active. If no earpiece device is available take the
|
||||
// first valid communication device
|
||||
if (device == null || !AudioDeviceBroker.isValidCommunicationDevice(device)) {
|
||||
device = getCommunicationDeviceOfType(AudioDeviceInfo.TYPE_BUILTIN_EARPIECE);
|
||||
if (device == null) {
|
||||
List<AudioDeviceInfo> commDevices = getAvailableCommunicationDevices();
|
||||
if (!commDevices.isEmpty()) {
|
||||
device = commDevices.get(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -918,8 +983,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
@GuardedBy("mDeviceStateLock")
|
||||
private void dispatchCommunicationDevice() {
|
||||
int portId = (mActiveCommunicationDevice == null) ? 0
|
||||
: mActiveCommunicationDevice.getId();
|
||||
AudioDeviceInfo device = getCommunicationDevice();
|
||||
int portId = device != null ? device.getId() : 0;
|
||||
if (portId == mCurCommunicationPortId) {
|
||||
return;
|
||||
}
|
||||
@@ -936,6 +1001,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
mCommDevDispatchers.finishBroadcast();
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Communication with (to) AudioService
|
||||
//TODO check whether the AudioService methods are candidates to move here
|
||||
|
||||
@@ -5846,46 +5846,16 @@ public class AudioService extends IAudioService.Stub
|
||||
restoreDeviceVolumeBehavior();
|
||||
}
|
||||
|
||||
private static final int[] VALID_COMMUNICATION_DEVICE_TYPES = {
|
||||
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
|
||||
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADSET,
|
||||
AudioDeviceInfo.TYPE_USB_HEADSET,
|
||||
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
|
||||
AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
|
||||
AudioDeviceInfo.TYPE_HEARING_AID,
|
||||
AudioDeviceInfo.TYPE_BLE_HEADSET,
|
||||
AudioDeviceInfo.TYPE_USB_DEVICE,
|
||||
AudioDeviceInfo.TYPE_BLE_SPEAKER,
|
||||
AudioDeviceInfo.TYPE_LINE_ANALOG,
|
||||
AudioDeviceInfo.TYPE_HDMI,
|
||||
AudioDeviceInfo.TYPE_AUX_LINE
|
||||
};
|
||||
|
||||
private boolean isValidCommunicationDevice(AudioDeviceInfo device) {
|
||||
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
|
||||
if (device.getType() == type) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @see AudioManager#getAvailableCommunicationDevices(int) */
|
||||
public int[] getAvailableCommunicationDeviceIds() {
|
||||
ArrayList<Integer> deviceIds = new ArrayList<>();
|
||||
AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
|
||||
for (AudioDeviceInfo device : devices) {
|
||||
if (isValidCommunicationDevice(device)) {
|
||||
deviceIds.add(device.getId());
|
||||
}
|
||||
}
|
||||
return deviceIds.stream().mapToInt(Integer::intValue).toArray();
|
||||
List<AudioDeviceInfo> commDevices = AudioDeviceBroker.getAvailableCommunicationDevices();
|
||||
return commDevices.stream().mapToInt(AudioDeviceInfo::getId).toArray();
|
||||
}
|
||||
/**
|
||||
* @see AudioManager#setCommunicationDevice(int)
|
||||
* @see AudioManager#clearCommunicationDevice()
|
||||
*/
|
||||
|
||||
/**
|
||||
* @see AudioManager#setCommunicationDevice(int)
|
||||
* @see AudioManager#clearCommunicationDevice()
|
||||
*/
|
||||
public boolean setCommunicationDevice(IBinder cb, int portId) {
|
||||
final int uid = Binder.getCallingUid();
|
||||
final int pid = Binder.getCallingPid();
|
||||
@@ -5897,7 +5867,7 @@ public class AudioService extends IAudioService.Stub
|
||||
Log.w(TAG, "setCommunicationDevice: invalid portID " + portId);
|
||||
return false;
|
||||
}
|
||||
if (!isValidCommunicationDevice(device)) {
|
||||
if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
|
||||
throw new IllegalArgumentException("invalid device type " + device.getType());
|
||||
}
|
||||
}
|
||||
@@ -5940,13 +5910,15 @@ public class AudioService extends IAudioService.Stub
|
||||
|
||||
/** @see AudioManager#getCommunicationDevice() */
|
||||
public int getCommunicationDevice() {
|
||||
int deviceId = 0;
|
||||
final long ident = Binder.clearCallingIdentity();
|
||||
AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
if (device == null) {
|
||||
return 0;
|
||||
try {
|
||||
AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
|
||||
deviceId = device != null ? device.getId() : 0;
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(ident);
|
||||
}
|
||||
return device.getId();
|
||||
return deviceId;
|
||||
}
|
||||
|
||||
/** @see AudioManager#addOnCommunicationDeviceChangedListener(
|
||||
|
||||
Reference in New Issue
Block a user