Loading android/app/src/com/android/bluetooth/a2dp/A2dpService.java +31 −39 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import static com.android.bluetooth.Utils.enforceCdmAssociation; import static com.android.bluetooth.Utils.hasBluetoothPrivilegedPermission; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.compat.CompatChanges; import android.bluetooth.BluetoothA2dp; Loading Loading @@ -90,7 +91,8 @@ public class A2dpService extends ProfileService { A2dpNativeInterface mA2dpNativeInterface; @VisibleForTesting ServiceFactory mFactory = new ServiceFactory(); private AudioManager mAudioManager; @VisibleForTesting AudioManager mAudioManager; private A2dpCodecConfig mA2dpCodecConfig; private CompanionDeviceManager mCompanionDeviceManager; Loading @@ -99,7 +101,7 @@ public class A2dpService extends ProfileService { private final ConcurrentMap<BluetoothDevice, A2dpStateMachine> mStateMachines = new ConcurrentHashMap<>(); // Protect setActiveDevice() so all invoked is handled squentially // Protect setActiveDevice()/removeActiveDevice() so all invoked is handled sequentially private final Object mActiveSwitchingGuard = new Object(); // Timeout for state machine thread join, to prevent potential ANR. Loading Loading @@ -186,7 +188,7 @@ public class A2dpService extends ProfileService { mAdapterService.notifyActivityAttributionInfo(getAttributionSource(), deviceAddress); // Step 9: Clear active device setActiveDevice(null); removeActiveDevice(false); return true; } Loading Loading @@ -487,38 +489,25 @@ public class A2dpService extends ProfileService { } } private void removeActiveDevice(boolean forceStopPlayingAudio) { /** * Removes the current active device. * * @param stopAudio whether the current media playback should be stopped. * @return true on success, otherwise false */ public boolean removeActiveDevice(boolean stopAudio) { synchronized (mActiveSwitchingGuard) { BluetoothDevice previousActiveDevice = null; synchronized (mStateMachines) { if (mActiveDevice == null) return; if (mActiveDevice == null) return true; previousActiveDevice = mActiveDevice; } int prevActiveConnectionState = getConnectionState(previousActiveDevice); // As per b/202602952, if we remove the active device due to a disconnection, // we need to check if another device is connected and set it active instead. // Calling this before any other active related calls has the same effect as // a classic active device switch. BluetoothDevice fallbackdevice = getFallbackDevice(); if (fallbackdevice != null && prevActiveConnectionState != BluetoothProfile.STATE_CONNECTED) { setActiveDevice(fallbackdevice); return; } // This needs to happen before we inform the audio manager that the device // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why. updateAndBroadcastActiveDevice(null); // Make sure the Audio Manager knows the previous Active device is disconnected. // However, if A2DP is still connected and not forcing stop audio for that remote // device, the user has explicitly switched the output to the local device and music // should continue playing. Otherwise, the remote device has been indeed disconnected // and audio should be suspended before switching the output to the local device. boolean stopAudio = forceStopPlayingAudio || (prevActiveConnectionState != BluetoothProfile.STATE_CONNECTED); // Make sure the Audio Manager knows the previous active device is no longer active. mAudioManager.handleBluetoothActiveDeviceChanged(null, previousActiveDevice, BluetoothProfileConnectionInfo.createA2dpInfo(!stopAudio, -1)); Loading @@ -527,9 +516,11 @@ public class A2dpService extends ProfileService { if (!mA2dpNativeInterface.setActiveDevice(null)) { Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native " + "layer"); return false; } } } return true; } /** Loading @@ -540,7 +531,7 @@ public class A2dpService extends ProfileService { * @return true on success, false on error */ @VisibleForTesting public boolean setSilenceMode(BluetoothDevice device, boolean silence) { public boolean setSilenceMode(@NonNull BluetoothDevice device, boolean silence) { if (DBG) { Log.d(TAG, "setSilenceMode(" + device + "): " + silence); } Loading @@ -560,17 +551,16 @@ public class A2dpService extends ProfileService { /** * Set the active device. * * @param device the active device * @param device the active device. Should not be null. * @return true on success, otherwise false */ public boolean setActiveDevice(BluetoothDevice device) { synchronized (mActiveSwitchingGuard) { public boolean setActiveDevice(@NonNull BluetoothDevice device) { if (device == null) { // Remove active device and continue playing audio only if necessary. removeActiveDevice(false); return true; Log.e(TAG, "device should not be null!"); return false; } synchronized (mActiveSwitchingGuard) { A2dpStateMachine sm = null; BluetoothDevice previousActiveDevice = null; synchronized (mStateMachines) { Loading Loading @@ -1256,10 +1246,8 @@ public class A2dpService extends ProfileService { if (toState == BluetoothProfile.STATE_CONNECTED && (mMaxConnectedAudioDevices == 1)) { setActiveDevice(device); } // Check if the active device is not connected anymore if (isActiveDevice(device) && (fromState == BluetoothProfile.STATE_CONNECTED)) { setActiveDevice(null); } // When disconnected, ActiveDeviceManager will call setActiveDevice(null) // Check if the device is disconnected - if unbond, remove the state machine if (toState == BluetoothProfile.STATE_DISCONNECTED) { if (mAdapterService.getBondState(device) == BluetoothDevice.BOND_NONE) { Loading Loading @@ -1393,8 +1381,12 @@ public class A2dpService extends ProfileService { A2dpService service = getService(source); boolean result = false; if (service != null) { if (device == null) { result = service.removeActiveDevice(false); } else { result = service.setActiveDevice(device); } } receiver.send(result); } catch (RuntimeException e) { receiver.propagateException(e); Loading android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcp; import android.annotation.NonNull; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; Loading Loading @@ -292,7 +293,7 @@ public class AvrcpTargetService extends ProfileService { return service.getActiveDevice(); } private void setA2dpActiveDevice(BluetoothDevice device) { private void setA2dpActiveDevice(@NonNull BluetoothDevice device) { A2dpService service = A2dpService.getA2dpService(); if (service == null) { Log.d(TAG, "setA2dpActiveDevice: A2dp service not found"); Loading Loading @@ -459,6 +460,7 @@ public class AvrcpTargetService extends ProfileService { Log.i(TAG, "setActiveDevice: device=" + device); if (device == null) { Log.wtf(TAG, "setActiveDevice: could not find device " + device); return; } setA2dpActiveDevice(device); } Loading android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +56 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.btservice; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.bluetooth.BluetoothA2dp; Loading Loading @@ -307,7 +309,7 @@ class ActiveDeviceManager { mHearingAidConnectedDevices.add(device); // New connected device: select it as active setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } Loading @@ -327,12 +329,12 @@ class ActiveDeviceManager { && mPendingLeHearingAidActiveDevice.isEmpty()) { // New connected device: select it as active setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } else if (mPendingLeHearingAidActiveDevice.contains(device)) { setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } Loading @@ -355,7 +357,7 @@ class ActiveDeviceManager { // New connected device: select it as active setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } Loading @@ -368,10 +370,9 @@ class ActiveDeviceManager { } mA2dpConnectedDevices.remove(device); if (Objects.equals(mA2dpActiveDevice, device)) { if (mA2dpConnectedDevices.isEmpty()) { setA2dpActiveDevice(null); if (!setFallbackDeviceActiveLocked()) { setA2dpActiveDevice(null, false); } setFallbackDeviceActiveLocked(); } } } Loading Loading @@ -487,7 +488,7 @@ class ActiveDeviceManager { } } if (device != null) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } Loading @@ -504,7 +505,7 @@ class ActiveDeviceManager { } // Just assign locally the new value if (device != null && !Objects.equals(mLeAudioActiveDevice, device)) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); } Loading @@ -522,7 +523,7 @@ class ActiveDeviceManager { } // Just assign locally the new value if (device != null && !Objects.equals(mLeHearingAidActiveDevice, device)) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); } Loading Loading @@ -633,18 +634,33 @@ class ActiveDeviceManager { return mHandlerThread.getLooper(); } private void setA2dpActiveDevice(BluetoothDevice device) { synchronized (mLock) { private void setA2dpActiveDevice(@NonNull BluetoothDevice device) { setA2dpActiveDevice(device, false); } private void setA2dpActiveDevice(@Nullable BluetoothDevice device, boolean hasFallbackDevice) { if (DBG) { Log.d(TAG, "setA2dpActiveDevice(" + device + ")"); Log.d(TAG, "setA2dpActiveDevice(" + device + ")" + (device == null ? " hasFallbackDevice=" + hasFallbackDevice : "")); } final A2dpService a2dpService = mFactory.getA2dpService(); if (a2dpService == null) { return; } if (!a2dpService.setActiveDevice(device)) { boolean success = false; if (device == null) { success = a2dpService.removeActiveDevice(!hasFallbackDevice); } else { success = a2dpService.setActiveDevice(device); } if (!success) { return; } synchronized (mLock) { mA2dpActiveDevice = device; } } Loading Loading @@ -733,13 +749,20 @@ class ActiveDeviceManager { } } private void setFallbackDeviceActiveLocked() { /** * TODO: This method can return true when a fallback device for an unrelated profile is found. * Take disconnected profile as an argument, and find the exact fallback device. * Also, split this method to smaller methods for better readability. * * @return true when the fallback device is activated, false otherwise */ private boolean setFallbackDeviceActiveLocked() { if (DBG) { Log.d(TAG, "setFallbackDeviceActive"); } DatabaseManager dbManager = mAdapterService.getDatabase(); if (dbManager == null) { return; return false; } List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>(); if (!mHearingAidConnectedDevices.isEmpty()) { Loading @@ -757,7 +780,7 @@ class ActiveDeviceManager { Log.d(TAG, "set hearing aid device active: " + device); } setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } else { Loading @@ -766,10 +789,10 @@ class ActiveDeviceManager { } setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } return; return true; } } Loading Loading @@ -820,7 +843,7 @@ class ActiveDeviceManager { Log.d(TAG, "set LE audio device active: " + device); } setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } else { Loading @@ -838,11 +861,15 @@ class ActiveDeviceManager { Log.d(TAG, "set LE audio device active: " + device); } setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } return true; } // No fallback device is found. return false; } private void resetState() { Loading Loading @@ -908,7 +935,7 @@ class ActiveDeviceManager { if (DBG) { Log.d(TAG, "wiredAudioDeviceConnected"); } setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); setLeAudioActiveDevice(null); Loading android/app/src/com/android/bluetooth/btservice/AdapterService.java +5 −1 Original line number Diff line number Diff line Loading @@ -5298,8 +5298,12 @@ public class AdapterService extends Service { || mA2dpService.getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { Log.i(TAG, "setActiveDevice: Setting active A2dp device " + device); if (device == null) { mA2dpService.removeActiveDevice(false); } else { mA2dpService.setActiveDevice(device); } } if (mHearingAidService != null && (device == null || mHearingAidService.getConnectionPolicy(device) Loading android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java +2 −3 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_READ; import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE; import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE; import static java.util.Map.entry; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; Loading Loading @@ -937,9 +935,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface + " request up"); } // TODO: Activate/deactivate devices with ActiveDeviceManager if (req.getOpcode() == Request.Opcodes.PLAY) { if (mAdapterService.getActiveDevices(BluetoothProfile.A2DP).size() > 0) { A2dpService.getA2dpService().setActiveDevice(null); A2dpService.getA2dpService().removeActiveDevice(false); } if (mAdapterService.getActiveDevices(BluetoothProfile.HEARING_AID).size() > 0) { HearingAidService.getHearingAidService().setActiveDevice(null); Loading Loading
android/app/src/com/android/bluetooth/a2dp/A2dpService.java +31 −39 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static com.android.bluetooth.Utils.enforceBluetoothPrivilegedPermission; import static com.android.bluetooth.Utils.enforceCdmAssociation; import static com.android.bluetooth.Utils.hasBluetoothPrivilegedPermission; import android.annotation.NonNull; import android.annotation.RequiresPermission; import android.app.compat.CompatChanges; import android.bluetooth.BluetoothA2dp; Loading Loading @@ -90,7 +91,8 @@ public class A2dpService extends ProfileService { A2dpNativeInterface mA2dpNativeInterface; @VisibleForTesting ServiceFactory mFactory = new ServiceFactory(); private AudioManager mAudioManager; @VisibleForTesting AudioManager mAudioManager; private A2dpCodecConfig mA2dpCodecConfig; private CompanionDeviceManager mCompanionDeviceManager; Loading @@ -99,7 +101,7 @@ public class A2dpService extends ProfileService { private final ConcurrentMap<BluetoothDevice, A2dpStateMachine> mStateMachines = new ConcurrentHashMap<>(); // Protect setActiveDevice() so all invoked is handled squentially // Protect setActiveDevice()/removeActiveDevice() so all invoked is handled sequentially private final Object mActiveSwitchingGuard = new Object(); // Timeout for state machine thread join, to prevent potential ANR. Loading Loading @@ -186,7 +188,7 @@ public class A2dpService extends ProfileService { mAdapterService.notifyActivityAttributionInfo(getAttributionSource(), deviceAddress); // Step 9: Clear active device setActiveDevice(null); removeActiveDevice(false); return true; } Loading Loading @@ -487,38 +489,25 @@ public class A2dpService extends ProfileService { } } private void removeActiveDevice(boolean forceStopPlayingAudio) { /** * Removes the current active device. * * @param stopAudio whether the current media playback should be stopped. * @return true on success, otherwise false */ public boolean removeActiveDevice(boolean stopAudio) { synchronized (mActiveSwitchingGuard) { BluetoothDevice previousActiveDevice = null; synchronized (mStateMachines) { if (mActiveDevice == null) return; if (mActiveDevice == null) return true; previousActiveDevice = mActiveDevice; } int prevActiveConnectionState = getConnectionState(previousActiveDevice); // As per b/202602952, if we remove the active device due to a disconnection, // we need to check if another device is connected and set it active instead. // Calling this before any other active related calls has the same effect as // a classic active device switch. BluetoothDevice fallbackdevice = getFallbackDevice(); if (fallbackdevice != null && prevActiveConnectionState != BluetoothProfile.STATE_CONNECTED) { setActiveDevice(fallbackdevice); return; } // This needs to happen before we inform the audio manager that the device // disconnected. Please see comment in updateAndBroadcastActiveDevice() for why. updateAndBroadcastActiveDevice(null); // Make sure the Audio Manager knows the previous Active device is disconnected. // However, if A2DP is still connected and not forcing stop audio for that remote // device, the user has explicitly switched the output to the local device and music // should continue playing. Otherwise, the remote device has been indeed disconnected // and audio should be suspended before switching the output to the local device. boolean stopAudio = forceStopPlayingAudio || (prevActiveConnectionState != BluetoothProfile.STATE_CONNECTED); // Make sure the Audio Manager knows the previous active device is no longer active. mAudioManager.handleBluetoothActiveDeviceChanged(null, previousActiveDevice, BluetoothProfileConnectionInfo.createA2dpInfo(!stopAudio, -1)); Loading @@ -527,9 +516,11 @@ public class A2dpService extends ProfileService { if (!mA2dpNativeInterface.setActiveDevice(null)) { Log.w(TAG, "setActiveDevice(null): Cannot remove active device in native " + "layer"); return false; } } } return true; } /** Loading @@ -540,7 +531,7 @@ public class A2dpService extends ProfileService { * @return true on success, false on error */ @VisibleForTesting public boolean setSilenceMode(BluetoothDevice device, boolean silence) { public boolean setSilenceMode(@NonNull BluetoothDevice device, boolean silence) { if (DBG) { Log.d(TAG, "setSilenceMode(" + device + "): " + silence); } Loading @@ -560,17 +551,16 @@ public class A2dpService extends ProfileService { /** * Set the active device. * * @param device the active device * @param device the active device. Should not be null. * @return true on success, otherwise false */ public boolean setActiveDevice(BluetoothDevice device) { synchronized (mActiveSwitchingGuard) { public boolean setActiveDevice(@NonNull BluetoothDevice device) { if (device == null) { // Remove active device and continue playing audio only if necessary. removeActiveDevice(false); return true; Log.e(TAG, "device should not be null!"); return false; } synchronized (mActiveSwitchingGuard) { A2dpStateMachine sm = null; BluetoothDevice previousActiveDevice = null; synchronized (mStateMachines) { Loading Loading @@ -1256,10 +1246,8 @@ public class A2dpService extends ProfileService { if (toState == BluetoothProfile.STATE_CONNECTED && (mMaxConnectedAudioDevices == 1)) { setActiveDevice(device); } // Check if the active device is not connected anymore if (isActiveDevice(device) && (fromState == BluetoothProfile.STATE_CONNECTED)) { setActiveDevice(null); } // When disconnected, ActiveDeviceManager will call setActiveDevice(null) // Check if the device is disconnected - if unbond, remove the state machine if (toState == BluetoothProfile.STATE_DISCONNECTED) { if (mAdapterService.getBondState(device) == BluetoothDevice.BOND_NONE) { Loading Loading @@ -1393,8 +1381,12 @@ public class A2dpService extends ProfileService { A2dpService service = getService(source); boolean result = false; if (service != null) { if (device == null) { result = service.removeActiveDevice(false); } else { result = service.setActiveDevice(device); } } receiver.send(result); } catch (RuntimeException e) { receiver.propagateException(e); Loading
android/app/src/com/android/bluetooth/avrcp/AvrcpTargetService.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.bluetooth.avrcp; import android.annotation.NonNull; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; Loading Loading @@ -292,7 +293,7 @@ public class AvrcpTargetService extends ProfileService { return service.getActiveDevice(); } private void setA2dpActiveDevice(BluetoothDevice device) { private void setA2dpActiveDevice(@NonNull BluetoothDevice device) { A2dpService service = A2dpService.getA2dpService(); if (service == null) { Log.d(TAG, "setA2dpActiveDevice: A2dp service not found"); Loading Loading @@ -459,6 +460,7 @@ public class AvrcpTargetService extends ProfileService { Log.i(TAG, "setActiveDevice: device=" + device); if (device == null) { Log.wtf(TAG, "setActiveDevice: could not find device " + device); return; } setA2dpActiveDevice(device); } Loading
android/app/src/com/android/bluetooth/btservice/ActiveDeviceManager.java +56 −29 Original line number Diff line number Diff line Loading @@ -16,6 +16,8 @@ package com.android.bluetooth.btservice; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.bluetooth.BluetoothA2dp; Loading Loading @@ -307,7 +309,7 @@ class ActiveDeviceManager { mHearingAidConnectedDevices.add(device); // New connected device: select it as active setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } Loading @@ -327,12 +329,12 @@ class ActiveDeviceManager { && mPendingLeHearingAidActiveDevice.isEmpty()) { // New connected device: select it as active setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } else if (mPendingLeHearingAidActiveDevice.contains(device)) { setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } Loading @@ -355,7 +357,7 @@ class ActiveDeviceManager { // New connected device: select it as active setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } Loading @@ -368,10 +370,9 @@ class ActiveDeviceManager { } mA2dpConnectedDevices.remove(device); if (Objects.equals(mA2dpActiveDevice, device)) { if (mA2dpConnectedDevices.isEmpty()) { setA2dpActiveDevice(null); if (!setFallbackDeviceActiveLocked()) { setA2dpActiveDevice(null, false); } setFallbackDeviceActiveLocked(); } } } Loading Loading @@ -487,7 +488,7 @@ class ActiveDeviceManager { } } if (device != null) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } Loading @@ -504,7 +505,7 @@ class ActiveDeviceManager { } // Just assign locally the new value if (device != null && !Objects.equals(mLeAudioActiveDevice, device)) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); } Loading @@ -522,7 +523,7 @@ class ActiveDeviceManager { } // Just assign locally the new value if (device != null && !Objects.equals(mLeHearingAidActiveDevice, device)) { setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); } Loading Loading @@ -633,18 +634,33 @@ class ActiveDeviceManager { return mHandlerThread.getLooper(); } private void setA2dpActiveDevice(BluetoothDevice device) { synchronized (mLock) { private void setA2dpActiveDevice(@NonNull BluetoothDevice device) { setA2dpActiveDevice(device, false); } private void setA2dpActiveDevice(@Nullable BluetoothDevice device, boolean hasFallbackDevice) { if (DBG) { Log.d(TAG, "setA2dpActiveDevice(" + device + ")"); Log.d(TAG, "setA2dpActiveDevice(" + device + ")" + (device == null ? " hasFallbackDevice=" + hasFallbackDevice : "")); } final A2dpService a2dpService = mFactory.getA2dpService(); if (a2dpService == null) { return; } if (!a2dpService.setActiveDevice(device)) { boolean success = false; if (device == null) { success = a2dpService.removeActiveDevice(!hasFallbackDevice); } else { success = a2dpService.setActiveDevice(device); } if (!success) { return; } synchronized (mLock) { mA2dpActiveDevice = device; } } Loading Loading @@ -733,13 +749,20 @@ class ActiveDeviceManager { } } private void setFallbackDeviceActiveLocked() { /** * TODO: This method can return true when a fallback device for an unrelated profile is found. * Take disconnected profile as an argument, and find the exact fallback device. * Also, split this method to smaller methods for better readability. * * @return true when the fallback device is activated, false otherwise */ private boolean setFallbackDeviceActiveLocked() { if (DBG) { Log.d(TAG, "setFallbackDeviceActive"); } DatabaseManager dbManager = mAdapterService.getDatabase(); if (dbManager == null) { return; return false; } List<BluetoothDevice> connectedHearingAidDevices = new ArrayList<>(); if (!mHearingAidConnectedDevices.isEmpty()) { Loading @@ -757,7 +780,7 @@ class ActiveDeviceManager { Log.d(TAG, "set hearing aid device active: " + device); } setHearingAidActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setLeAudioActiveDevice(null); } else { Loading @@ -766,10 +789,10 @@ class ActiveDeviceManager { } setLeHearingAidActiveDevice(device); setHearingAidActiveDevice(null); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } return; return true; } } Loading Loading @@ -820,7 +843,7 @@ class ActiveDeviceManager { Log.d(TAG, "set LE audio device active: " + device); } setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } else { Loading @@ -838,11 +861,15 @@ class ActiveDeviceManager { Log.d(TAG, "set LE audio device active: " + device); } setLeAudioActiveDevice(device); setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); } } return true; } // No fallback device is found. return false; } private void resetState() { Loading Loading @@ -908,7 +935,7 @@ class ActiveDeviceManager { if (DBG) { Log.d(TAG, "wiredAudioDeviceConnected"); } setA2dpActiveDevice(null); setA2dpActiveDevice(null, true); setHfpActiveDevice(null); setHearingAidActiveDevice(null); setLeAudioActiveDevice(null); Loading
android/app/src/com/android/bluetooth/btservice/AdapterService.java +5 −1 Original line number Diff line number Diff line Loading @@ -5298,8 +5298,12 @@ public class AdapterService extends Service { || mA2dpService.getConnectionPolicy(device) == BluetoothProfile.CONNECTION_POLICY_ALLOWED)) { Log.i(TAG, "setActiveDevice: Setting active A2dp device " + device); if (device == null) { mA2dpService.removeActiveDevice(false); } else { mA2dpService.setActiveDevice(device); } } if (mHearingAidService != null && (device == null || mHearingAidService.getConnectionPolicy(device) Loading
android/app/src/com/android/bluetooth/mcp/MediaControlGattService.java +2 −3 Original line number Diff line number Diff line Loading @@ -25,8 +25,6 @@ import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_READ; import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE; import static android.bluetooth.BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE; import static java.util.Map.entry; import android.annotation.NonNull; import android.annotation.Nullable; import android.bluetooth.BluetoothAdapter; Loading Loading @@ -937,9 +935,10 @@ public class MediaControlGattService implements MediaControlGattServiceInterface + " request up"); } // TODO: Activate/deactivate devices with ActiveDeviceManager if (req.getOpcode() == Request.Opcodes.PLAY) { if (mAdapterService.getActiveDevices(BluetoothProfile.A2DP).size() > 0) { A2dpService.getA2dpService().setActiveDevice(null); A2dpService.getA2dpService().removeActiveDevice(false); } if (mAdapterService.getActiveDevices(BluetoothProfile.HEARING_AID).size() > 0) { HearingAidService.getHearingAidService().setActiveDevice(null); Loading