Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1dea0dab authored by Eric Laurent's avatar Eric Laurent
Browse files

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
parent 7f5fddd3
Loading
Loading
Loading
Loading
+69 −3
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.server.utils.EventLogger;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
@@ -453,6 +454,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.
@@ -460,7 +503,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;
        }
    }

@@ -942,8 +1007,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;
        }
@@ -960,6 +1025,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
        mCommDevDispatchers.finishBroadcast();
    }


    //---------------------------------------------------------------------
    // Communication with (to) AudioService
    //TODO check whether the AudioService methods are candidates to move here
+12 −47
Original line number Diff line number Diff line
@@ -6067,45 +6067,12 @@ 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) {
        if (!device.isSink()) {
            return false;
        }
        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()
@@ -6120,7 +6087,7 @@ public class AudioService extends IAudioService.Stub
            if (device == null) {
                throw new IllegalArgumentException("invalid portID " + portId);
            }
            if (!isValidCommunicationDevice(device)) {
            if (!AudioDeviceBroker.isValidCommunicationDevice(device)) {
                if (!device.isSink()) {
                    throw new IllegalArgumentException("device must have sink role");
                } else {
@@ -6168,17 +6135,15 @@ public class AudioService extends IAudioService.Stub
    /** @see AudioManager#getCommunicationDevice() */
    public int getCommunicationDevice() {
        AudioDeviceInfo device = null;
        int deviceId = 0;
        final long ident = Binder.clearCallingIdentity();
        try {
            device = mDeviceBroker.getCommunicationDevice();
            AudioDeviceInfo device = mDeviceBroker.getCommunicationDevice();
            deviceId = device != null ? device.getId() : 0;
        } finally {
            Binder.restoreCallingIdentity(ident);
        }
        if (device == null) {
            return 0;
        }
        return device.getId();
        return deviceId;
    }
    /** @see AudioManager#addOnCommunicationDeviceChangedListener(