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
This commit is contained in:
@@ -58,6 +58,7 @@ import com.android.internal.annotations.GuardedBy;
|
|||||||
import com.android.server.utils.EventLogger;
|
import com.android.server.utils.EventLogger;
|
||||||
|
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
@@ -453,6 +454,48 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
return device;
|
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.
|
* Returns the device currently requested for communication use case.
|
||||||
* @return AudioDeviceInfo the requested device for communication.
|
* @return AudioDeviceInfo the requested device for communication.
|
||||||
@@ -460,7 +503,29 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
/* package */ AudioDeviceInfo getCommunicationDevice() {
|
/* package */ AudioDeviceInfo getCommunicationDevice() {
|
||||||
synchronized (mDeviceStateLock) {
|
synchronized (mDeviceStateLock) {
|
||||||
updateActiveCommunicationDevice();
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,8 +1007,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
|
|
||||||
@GuardedBy("mDeviceStateLock")
|
@GuardedBy("mDeviceStateLock")
|
||||||
private void dispatchCommunicationDevice() {
|
private void dispatchCommunicationDevice() {
|
||||||
int portId = (mActiveCommunicationDevice == null) ? 0
|
AudioDeviceInfo device = getCommunicationDevice();
|
||||||
: mActiveCommunicationDevice.getId();
|
int portId = device != null ? device.getId() : 0;
|
||||||
if (portId == mCurCommunicationPortId) {
|
if (portId == mCurCommunicationPortId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -960,6 +1025,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
|||||||
mCommDevDispatchers.finishBroadcast();
|
mCommDevDispatchers.finishBroadcast();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------
|
//---------------------------------------------------------------------
|
||||||
// Communication with (to) AudioService
|
// Communication with (to) AudioService
|
||||||
//TODO check whether the AudioService methods are candidates to move here
|
//TODO check whether the AudioService methods are candidates to move here
|
||||||
|
|||||||
@@ -6067,45 +6067,12 @@ public class AudioService extends IAudioService.Stub
|
|||||||
restoreDeviceVolumeBehavior();
|
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) {
|
|
||||||
if (!device.isSink()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int type : VALID_COMMUNICATION_DEVICE_TYPES) {
|
|
||||||
if (device.getType() == type) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @see AudioManager#getAvailableCommunicationDevices(int) */
|
/** @see AudioManager#getAvailableCommunicationDevices(int) */
|
||||||
public int[] getAvailableCommunicationDeviceIds() {
|
public int[] getAvailableCommunicationDeviceIds() {
|
||||||
ArrayList<Integer> deviceIds = new ArrayList<>();
|
List<AudioDeviceInfo> commDevices = AudioDeviceBroker.getAvailableCommunicationDevices();
|
||||||
AudioDeviceInfo[] devices = AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
|
return commDevices.stream().mapToInt(AudioDeviceInfo::getId).toArray();
|
||||||
for (AudioDeviceInfo device : devices) {
|
|
||||||
if (isValidCommunicationDevice(device)) {
|
|
||||||
deviceIds.add(device.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return deviceIds.stream().mapToInt(Integer::intValue).toArray();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see AudioManager#setCommunicationDevice(int)
|
* @see AudioManager#setCommunicationDevice(int)
|
||||||
* @see AudioManager#clearCommunicationDevice()
|
* @see AudioManager#clearCommunicationDevice()
|
||||||
@@ -6120,7 +6087,7 @@ public class AudioService extends IAudioService.Stub
|
|||||||
if (device == null) {
|
if (device == null) {
|
||||||
throw new IllegalArgumentException("invalid portID " + portId);
|
throw new IllegalArgumentException("invalid portID " + portId);
|
||||||
}
|
}
|
||||||
if (!isValidCommunicationDevice(device)) {
|
if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
|
||||||
if (!device.isSink()) {
|
if (!device.isSink()) {
|
||||||
throw new IllegalArgumentException("device must have sink role");
|
throw new IllegalArgumentException("device must have sink role");
|
||||||
} else {
|
} else {
|
||||||
@@ -6168,17 +6135,15 @@ public class AudioService extends IAudioService.Stub
|
|||||||
|
|
||||||
/** @see AudioManager#getCommunicationDevice() */
|
/** @see AudioManager#getCommunicationDevice() */
|
||||||
public int getCommunicationDevice() {
|
public int getCommunicationDevice() {
|
||||||
AudioDeviceInfo device = null;
|
int deviceId = 0;
|
||||||
final long ident = Binder.clearCallingIdentity();
|
final long ident = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
device = mDeviceBroker.getCommunicationDevice();
|
AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
|
||||||
|
deviceId = device != null ? device.getId() : 0;
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(ident);
|
Binder.restoreCallingIdentity(ident);
|
||||||
}
|
}
|
||||||
if (device == null) {
|
return deviceId;
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return device.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see AudioManager#addOnCommunicationDeviceChangedListener(
|
/** @see AudioManager#addOnCommunicationDeviceChangedListener(
|
||||||
|
|||||||
Reference in New Issue
Block a user