Merge "[Audiosharing] Move time consuming work to background." into main
diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
index 9329cc29..70859c2 100644
--- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
+++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDevicePreferenceController.java
@@ -47,6 +47,9 @@
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
 import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcastAssistant;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.utils.ThreadUtils;
+
+import com.google.common.collect.ImmutableList;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -260,6 +263,9 @@
             return;
         }
         mLocalBtManager.getEventManager().registerCallback(this);
+        if (DEBUG) {
+            Log.d(TAG, "onStart() Register callbacks for broadcast and assistant.");
+        }
         mBroadcast.registerServiceCallBack(mExecutor, mBroadcastCallback);
         mAssistant.registerServiceCallBack(mExecutor, mBroadcastAssistantCallback);
         mBluetoothDeviceUpdater.registerCallback();
@@ -281,15 +287,11 @@
             return;
         }
         mLocalBtManager.getEventManager().unregisterCallback(this);
-        // TODO: verify the reason for failing to unregister
-        try {
-            mBroadcast.unregisterServiceCallBack(mBroadcastCallback);
-            mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
-        } catch (IllegalArgumentException e) {
-            Log.e(
-                    TAG,
-                    "Fail to unregister broadcast or assistant callback due to " + e.getMessage());
+        if (DEBUG) {
+            Log.d(TAG, "onStop() Unregister callbacks for broadcast and assistant.");
         }
+        mBroadcast.unregisterServiceCallBack(mBroadcastCallback);
+        mAssistant.unregisterServiceCallBack(mBroadcastAssistantCallback);
         mBluetoothDeviceUpdater.unregisterCallback();
     }
 
@@ -358,6 +360,28 @@
                     "Ignore onProfileConnectionStateChanged, no broadcast or assistant supported");
             return;
         }
+        var unused =
+                ThreadUtils.postOnBackgroundThread(
+                        () -> handleOnProfileStateChanged(cachedDevice, bluetoothProfile));
+    }
+
+    /**
+     * Initialize the controller.
+     *
+     * @param fragment The fragment to provide the context and metrics category for {@link
+     *     AudioSharingBluetoothDeviceUpdater} and provide the host for dialogs.
+     */
+    public void init(DashboardFragment fragment) {
+        mFragment = fragment;
+        mBluetoothDeviceUpdater =
+                new AudioSharingBluetoothDeviceUpdater(
+                        fragment.getContext(),
+                        AudioSharingDevicePreferenceController.this,
+                        fragment.getMetricsCategory());
+    }
+
+    private void handleOnProfileStateChanged(
+            @NonNull CachedBluetoothDevice cachedDevice, int bluetoothProfile) {
         boolean isLeAudioSupported = isLeAudioSupported(cachedDevice);
         // For eligible (LE audio) remote device, we only check its connected LE audio profile.
         if (isLeAudioSupported && bluetoothProfile != BluetoothProfile.LE_AUDIO) {
@@ -384,120 +408,143 @@
         }
         if (!isLeAudioSupported) {
             // Handle connected ineligible (non LE audio) remote device
-            if (isBroadcasting()) {
-                // Show stop audio sharing dialog when an ineligible (non LE audio) remote device
-                // connected during a sharing session.
-                closeOpeningDialogs();
-                AudioSharingStopDialogFragment.show(
-                        mFragment,
-                        cachedDevice.getName(),
-                        () -> mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId()));
-            } else {
-                // Do nothing for ineligible (non LE audio) remote device when no sharing session.
-                if (DEBUG) {
-                    Log.d(
-                            TAG,
-                            "Ignore onProfileConnectionStateChanged for non LE audio without"
-                                + " sharing session");
-                }
-            }
+            handleOnProfileStateChangedForNonLeAudioDevice(cachedDevice);
         } else {
-            Map<Integer, List<CachedBluetoothDevice>> groupedDevices =
-                    AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
             // Handle connected eligible (LE audio) remote device
-            if (isBroadcasting()) {
-                // Show audio sharing switch or join dialog according to device count in the sharing
-                // session.
-                ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
-                        AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
-                                mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
-                // Show audio sharing switch dialog when the third eligible (LE audio) remote device
-                // connected during a sharing session.
-                if (deviceItemsInSharingSession.size() >= 2) {
-                    closeOpeningDialogs();
-                    AudioSharingDisconnectDialogFragment.show(
-                            mFragment,
-                            deviceItemsInSharingSession,
-                            cachedDevice.getName(),
-                            (AudioSharingDeviceItem item) -> {
-                                // Remove all sources from the device user clicked
-                                for (CachedBluetoothDevice device :
-                                        groupedDevices.get(item.getGroupId())) {
-                                    for (BluetoothLeBroadcastReceiveState source :
-                                            mAssistant.getAllSources(device.getDevice())) {
-                                        mAssistant.removeSource(
-                                                device.getDevice(), source.getSourceId());
-                                    }
-                                }
-                                // Add current broadcast to the latest connected device
-                                mAssistant.addSource(
-                                        cachedDevice.getDevice(),
-                                        mBroadcast.getLatestBluetoothLeBroadcastMetadata(),
-                                        /* isGroupOp= */ true);
-                            });
-                } else {
-                    // Show audio sharing join dialog when the first or second eligible (LE audio)
-                    // remote device connected during a sharing session.
-                    closeOpeningDialogs();
-                    AudioSharingJoinDialogFragment.show(
-                            mFragment,
-                            deviceItemsInSharingSession,
-                            cachedDevice.getName(),
-                            () -> {
-                                // Add current broadcast to the latest connected device
-                                mAssistant.addSource(
-                                        cachedDevice.getDevice(),
-                                        mBroadcast.getLatestBluetoothLeBroadcastMetadata(),
-                                        /* isGroupOp= */ true);
-                            });
-                }
-            } else {
-                ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
-                for (List<CachedBluetoothDevice> devices : groupedDevices.values()) {
-                    // Use random device in the group within the sharing session to
-                    // represent the group.
-                    CachedBluetoothDevice device = devices.get(0);
-                    if (device.getGroupId() == cachedDevice.getGroupId()) {
-                        continue;
-                    }
-                    deviceItems.add(AudioSharingUtils.buildAudioSharingDeviceItem(device));
-                }
-                // Show audio sharing join dialog when the second eligible (LE audio) remote device
-                // connect and no sharing session.
-                if (deviceItems.size() == 1) {
-                    closeOpeningDialogs();
-                    AudioSharingJoinDialogFragment.show(
-                            mFragment,
-                            deviceItems,
-                            cachedDevice.getName(),
-                            () -> {
-                                mTargetSinks = new ArrayList<>();
-                                for (List<CachedBluetoothDevice> devices :
-                                        groupedDevices.values()) {
-                                    for (CachedBluetoothDevice device : devices) {
-                                        mTargetSinks.add(device.getDevice());
-                                    }
-                                }
-                                mBroadcast.startBroadcast("test", null);
-                            });
-                }
+            handleOnProfileStateChangedForLeAudioDevice(cachedDevice);
+        }
+    }
+
+    private void handleOnProfileStateChangedForNonLeAudioDevice(
+            @NonNull CachedBluetoothDevice cachedDevice) {
+        if (isBroadcasting()) {
+            // Show stop audio sharing dialog when an ineligible (non LE audio) remote device
+            // connected during a sharing session.
+            ThreadUtils.postOnMainThread(
+                    () -> {
+                        closeOpeningDialogs();
+                        AudioSharingStopDialogFragment.show(
+                                mFragment,
+                                cachedDevice.getName(),
+                                () -> mBroadcast.stopBroadcast(mBroadcast.getLatestBroadcastId()));
+                    });
+        } else {
+            // Do nothing for ineligible (non LE audio) remote device when no sharing session.
+            if (DEBUG) {
+                Log.d(
+                        TAG,
+                        "Ignore onProfileConnectionStateChanged for non LE audio without"
+                                + " sharing session");
             }
         }
     }
 
-    /**
-     * Initialize the controller.
-     *
-     * @param fragment The fragment to provide the context and metrics category for {@link
-     *     AudioSharingBluetoothDeviceUpdater} and provide the host for dialogs.
-     */
-    public void init(DashboardFragment fragment) {
-        mFragment = fragment;
-        mBluetoothDeviceUpdater =
-                new AudioSharingBluetoothDeviceUpdater(
-                        fragment.getContext(),
-                        AudioSharingDevicePreferenceController.this,
-                        fragment.getMetricsCategory());
+    private void handleOnProfileStateChangedForLeAudioDevice(
+            @NonNull CachedBluetoothDevice cachedDevice) {
+        Map<Integer, List<CachedBluetoothDevice>> groupedDevices =
+                AudioSharingUtils.fetchConnectedDevicesByGroupId(mLocalBtManager);
+        if (isBroadcasting()) {
+            if (groupedDevices.containsKey(cachedDevice.getGroupId())
+                    && groupedDevices.get(cachedDevice.getGroupId()).stream()
+                            .anyMatch(
+                                    device ->
+                                            AudioSharingUtils.hasBroadcastSource(
+                                                    device, mLocalBtManager))) {
+                Log.d(
+                        TAG,
+                        "Automatically add another device within the same group to the sharing: "
+                                + cachedDevice.getDevice().getAnonymizedAddress());
+                addSourceToTargetDevices(ImmutableList.of(cachedDevice.getDevice()));
+                return;
+            }
+            // Show audio sharing switch or join dialog according to device count in the sharing
+            // session.
+            ArrayList<AudioSharingDeviceItem> deviceItemsInSharingSession =
+                    AudioSharingUtils.buildOrderedConnectedLeadAudioSharingDeviceItem(
+                            mLocalBtManager, groupedDevices, /* filterByInSharing= */ true);
+            // Show audio sharing switch dialog when the third eligible (LE audio) remote device
+            // connected during a sharing session.
+            if (deviceItemsInSharingSession.size() >= 2) {
+                ThreadUtils.postOnMainThread(
+                        () -> {
+                            closeOpeningDialogs();
+                            AudioSharingDisconnectDialogFragment.show(
+                                    mFragment,
+                                    deviceItemsInSharingSession,
+                                    cachedDevice.getName(),
+                                    (AudioSharingDeviceItem item) -> {
+                                        // Remove all sources from the device user clicked
+                                        if (groupedDevices.containsKey(item.getGroupId())) {
+                                            for (CachedBluetoothDevice device :
+                                                    groupedDevices.get(item.getGroupId())) {
+                                                for (BluetoothLeBroadcastReceiveState source :
+                                                        mAssistant.getAllSources(
+                                                                device.getDevice())) {
+                                                    mAssistant.removeSource(
+                                                            device.getDevice(),
+                                                            source.getSourceId());
+                                                }
+                                            }
+                                        }
+                                        // Add current broadcast to the latest connected device
+                                        mAssistant.addSource(
+                                                cachedDevice.getDevice(),
+                                                mBroadcast.getLatestBluetoothLeBroadcastMetadata(),
+                                                /* isGroupOp= */ true);
+                                    });
+                        });
+            } else {
+                // Show audio sharing join dialog when the first or second eligible (LE audio)
+                // remote device connected during a sharing session.
+                ThreadUtils.postOnMainThread(
+                        () -> {
+                            closeOpeningDialogs();
+                            AudioSharingJoinDialogFragment.show(
+                                    mFragment,
+                                    deviceItemsInSharingSession,
+                                    cachedDevice.getName(),
+                                    () -> {
+                                        // Add current broadcast to the latest connected device
+                                        mAssistant.addSource(
+                                                cachedDevice.getDevice(),
+                                                mBroadcast.getLatestBluetoothLeBroadcastMetadata(),
+                                                /* isGroupOp= */ true);
+                                    });
+                        });
+            }
+        } else {
+            ArrayList<AudioSharingDeviceItem> deviceItems = new ArrayList<>();
+            for (List<CachedBluetoothDevice> devices : groupedDevices.values()) {
+                // Use random device in the group within the sharing session to represent the group.
+                CachedBluetoothDevice device = devices.get(0);
+                if (device.getGroupId() == cachedDevice.getGroupId()) {
+                    continue;
+                }
+                deviceItems.add(AudioSharingUtils.buildAudioSharingDeviceItem(device));
+            }
+            // Show audio sharing join dialog when the second eligible (LE audio) remote
+            // device connect and no sharing session.
+            if (deviceItems.size() == 1) {
+                ThreadUtils.postOnMainThread(
+                        () -> {
+                            closeOpeningDialogs();
+                            AudioSharingJoinDialogFragment.show(
+                                    mFragment,
+                                    deviceItems,
+                                    cachedDevice.getName(),
+                                    () -> {
+                                        mTargetSinks = new ArrayList<>();
+                                        for (List<CachedBluetoothDevice> devices :
+                                                groupedDevices.values()) {
+                                            for (CachedBluetoothDevice device : devices) {
+                                                mTargetSinks.add(device.getDevice());
+                                            }
+                                        }
+                                        mBroadcast.startBroadcast("test", null);
+                                    });
+                        });
+            }
+        }
     }
 
     private boolean isLeAudioSupported(CachedBluetoothDevice cachedDevice) {