Loading src/com/android/server/telecom/CallAudioRouteController.java +77 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -812,6 +831,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter { break; } } } if (bluetoothRoute != null && bluetoothDevice != null) { if (mFocusType == RINGING_FOCUS) { Loading @@ -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)) { Loading @@ -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() { Loading Loading @@ -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)) { Loading Loading @@ -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) { Loading src/com/android/server/telecom/PendingAudioRoute.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = Loading src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
src/com/android/server/telecom/CallAudioRouteController.java +77 −10 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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(); Loading Loading @@ -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); Loading Loading @@ -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; Loading @@ -812,6 +831,7 @@ public class CallAudioRouteController implements CallAudioRouteAdapter { break; } } } if (bluetoothRoute != null && bluetoothDevice != null) { if (mFocusType == RINGING_FOCUS) { Loading @@ -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)) { Loading @@ -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() { Loading Loading @@ -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)) { Loading Loading @@ -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) { Loading
src/com/android/server/telecom/PendingAudioRoute.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; } Loading
src/com/android/server/telecom/bluetooth/BluetoothDeviceManager.java +2 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 = Loading
src/com/android/server/telecom/bluetooth/BluetoothStateReceiver.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 Loading