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

Commit 06e6d4b3 authored by Pranav Madapurmath's avatar Pranav Madapurmath Committed by Android (Google) Code Review
Browse files

Merge "Resolve WhatsApp audio route switching" into main

parents a1e232b1 507768c2
Loading
Loading
Loading
Loading
+77 −10
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import com.android.internal.util.IndentingPrintWriter;
import com.android.server.telecom.bluetooth.BluetoothRouteManager;
import com.android.server.telecom.flags.FeatureFlags;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -76,6 +77,9 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        ROUTE_MAP.put(AudioRoute.TYPE_STREAMING, CallAudioState.ROUTE_STREAMING);
    }

    /** Valid values for the first argument for SWITCH_BASELINE_ROUTE */
    public static final int INCLUDE_BLUETOOTH_IN_BASELINE = 1;

    private final CallsManager mCallsManager;
    private final Context mContext;
    private AudioManager mAudioManager;
@@ -91,6 +95,8 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
    private AudioRoute mStreamingRoute;
    private Set<AudioRoute> mStreamingRoutes;
    private Map<AudioRoute, BluetoothDevice> mBluetoothRoutes;
    private Pair<Integer, String> mActiveBluetoothDevice;
    private Map<Integer, String> mActiveDeviceCache;
    private Map<Integer, AudioRoute> mTypeRoutes;
    private PendingAudioRoute mPendingAudioRoute;
    private AudioRoute.Factory mAudioRouteFactory;
@@ -260,9 +266,13 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
                            handleSwitchSpeaker();
                            break;
                        case SWITCH_BASELINE_ROUTE:
                        case USER_SWITCH_BASELINE_ROUTE:
                            address = (String) ((SomeArgs) msg.obj).arg2;
                            handleSwitchBaselineRoute(address);
                            handleSwitchBaselineRoute(msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE,
                                    address);
                            break;
                        case USER_SWITCH_BASELINE_ROUTE:
                            handleSwitchBaselineRoute(msg.arg1 == INCLUDE_BLUETOOTH_IN_BASELINE,
                                    null);
                            break;
                        case SPEAKER_ON:
                            handleSpeakerOn();
@@ -312,6 +322,11 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
    public void initialize() {
        mAvailableRoutes = new HashSet<>();
        mBluetoothRoutes = new LinkedHashMap<>();
        mActiveDeviceCache = new HashMap<>();
        mActiveDeviceCache.put(AudioRoute.TYPE_BLUETOOTH_SCO, null);
        mActiveDeviceCache.put(AudioRoute.TYPE_BLUETOOTH_HA, null);
        mActiveDeviceCache.put(AudioRoute.TYPE_BLUETOOTH_LE, null);
        mActiveBluetoothDevice = null;
        mTypeRoutes = new ArrayMap<>();
        mStreamingRoutes = new HashSet<>();
        mPendingAudioRoute = new PendingAudioRoute(this, mAudioManager, mBluetoothRouteManager);
@@ -805,6 +820,10 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        Log.i(this, "handle switch to bluetooth with address %s", address);
        AudioRoute bluetoothRoute = null;
        BluetoothDevice bluetoothDevice = null;
        if (address == null) {
            bluetoothRoute = getArbitraryBluetoothDevice();
            bluetoothDevice = mBluetoothRoutes.get(bluetoothRoute);
        } else {
            for (AudioRoute route : getAvailableRoutes()) {
                if (Objects.equals(address, route.getBluetoothAddress())) {
                    bluetoothRoute = route;
@@ -812,6 +831,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
                    break;
                }
            }
        }

        if (bluetoothRoute != null && bluetoothDevice != null) {
            if (mFocusType == RINGING_FOCUS) {
@@ -825,6 +845,20 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        }
    }

    /**
     * Retrieve the active BT device, if available, otherwise return the most recently tracked
     * active device, or null if none are available.
     * @return {@link AudioRoute} of the BT device.
     */
    private AudioRoute getArbitraryBluetoothDevice() {
        if (mActiveBluetoothDevice != null) {
            return getBluetoothRoute(mActiveBluetoothDevice.first, mActiveBluetoothDevice.second);
        } else if (!mBluetoothRoutes.isEmpty()) {
            return mBluetoothRoutes.keySet().stream().toList().get(mBluetoothRoutes.size() - 1);
        }
        return null;
    }

    private void handleSwitchHeadset() {
        AudioRoute headsetRoute = mTypeRoutes.get(AudioRoute.TYPE_WIRED);
        if (headsetRoute != null && getAvailableRoutes().contains(headsetRoute)) {
@@ -842,8 +876,8 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        }
    }

    private void handleSwitchBaselineRoute(String btAddressToExclude) {
        routeTo(mIsActive, getBaseRoute(true, btAddressToExclude));
    private void handleSwitchBaselineRoute(boolean includeBluetooth, String btAddressToExclude) {
        routeTo(mIsActive, getBaseRoute(includeBluetooth, btAddressToExclude));
    }

    private void handleSpeakerOn() {
@@ -1085,7 +1119,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {

    public AudioRoute getBaseRoute(boolean includeBluetooth, String btAddressToExclude) {
        AudioRoute destRoute = getPreferredAudioRouteFromStrategy();
        if (destRoute == null) {
        if (destRoute == null || (destRoute.getBluetoothAddress() != null && !includeBluetooth)) {
            destRoute = getPreferredAudioRouteFromDefault(includeBluetooth, btAddressToExclude);
        }
        if (destRoute != null && !getAvailableRoutes().contains(destRoute)) {
@@ -1243,6 +1277,39 @@ public class CallAudioRouteController implements CallAudioRouteAdapter {
        mIsScoAudioConnected = value;
    }

    /**
     * Update the active bluetooth device being tracked (as well as for individual profiles).
     * We need to keep track of active devices for individual profiles because of potential
     * inconsistencies found in BluetoothStateReceiver#handleActiveDeviceChanged. When multiple
     * profiles are paired, we could have a scenario where an active device A is replaced
     * with an active device B (from a different profile), which is then removed as an active
     * device shortly after, causing device A to be reactive. It's possible that the active device
     * changed intent is never received again for device A so an active device cache is necessary
     * to track these devices at a profile level.
     * @param device {@link Pair} containing the BT audio route type (i.e. SCO/HA/LE) and the
     *                           address of the device.
     */
    public void updateActiveBluetoothDevice(Pair<Integer, String> device) {
        mActiveDeviceCache.put(device.first, device.second);
        // Update most recently active device if address isn't null (meaning some device is active).
        if (device.second != null) {
            mActiveBluetoothDevice = device;
        } else {
            // If a device was removed, check to ensure that no other device is still considered
            // active.
            boolean hasActiveDevice = false;
            for (String address : mActiveDeviceCache.values()) {
                if (address != null) {
                    hasActiveDevice = true;
                    break;
                }
            }
            if (!hasActiveDevice) {
                mActiveBluetoothDevice = null;
            }
        }
    }

    @VisibleForTesting
    public void setActive(boolean active) {
        if (active) {
+2 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.telecom;

import static com.android.server.telecom.CallAudioRouteAdapter.PENDING_ROUTE_FAILED;
import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
import static com.android.server.telecom.CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE;

import android.bluetooth.BluetoothDevice;
import android.media.AudioManager;
@@ -96,7 +97,7 @@ public class PendingAudioRoute {
        if (message.first == PENDING_ROUTE_FAILED) {
            // Fallback to base route
            mCallAudioRouteController.sendMessageWithSessionInfo(
                    SWITCH_BASELINE_ROUTE, 0, btAddressToExclude);
                    SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE, btAddressToExclude);
            return;
        }

+2 −1
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static com.android.server.telecom.AudioRoute.TYPE_BLUETOOTH_HA;
import static com.android.server.telecom.AudioRoute.TYPE_BLUETOOTH_SCO;
import static com.android.server.telecom.CallAudioRouteAdapter.BT_DEVICE_REMOVED;
import static com.android.server.telecom.CallAudioRouteAdapter.SWITCH_BASELINE_ROUTE;
import static com.android.server.telecom.CallAudioRouteController.INCLUDE_BLUETOOTH_IN_BASELINE;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
@@ -257,7 +258,7 @@ public class BluetoothDeviceManager {
                    BT_DEVICE_REMOVED, route.getType(), device);
        }
        mCallAudioRouteAdapter.sendMessageWithSessionInfo(
                SWITCH_BASELINE_ROUTE, 0, (String) null);
                SWITCH_BASELINE_ROUTE, INCLUDE_BLUETOOTH_IN_BASELINE, (String) null);
    }

    private final LinkedHashMap<String, BluetoothDevice> mHfpDevicesByAddress =
+5 −0
Original line number Diff line number Diff line
@@ -236,10 +236,15 @@ public class BluetoothStateReceiver extends BroadcastReceiver {
                BluetoothDeviceManager.getDeviceTypeString(deviceType));

        if (Flags.useRefactoredAudioRouteSwitching()) {
            CallAudioRouteController audioRouteController = (CallAudioRouteController)
                    mCallAudioRouteAdapter;
            if (device == null) {
                audioRouteController.updateActiveBluetoothDevice(new Pair(audioRouteType, null));
                mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_ACTIVE_DEVICE_GONE,
                        audioRouteType);
            } else {
                audioRouteController.updateActiveBluetoothDevice(
                        new Pair(audioRouteType, device.getAddress()));
                mCallAudioRouteAdapter.sendMessageWithSessionInfo(BT_ACTIVE_DEVICE_PRESENT,
                        audioRouteType, device.getAddress());
                if (deviceType == BluetoothDeviceManager.DEVICE_TYPE_HEARING_AID