Merge changes I094ba6be,Idbdd21a1,I03dfdc25,I40afabb0,I01e0ec91, ...

* changes:
  Update the LE audio device into the media device category
  Handle csip set member automatic pair in Setting
  Do not update the previously connected devices for the sub device
  Accept the pairing request automatically for the set member pairing
  Show the multiple Mac address for the coordinated set
  Add the pairing string for CSIP supported device
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index e10b17d..ec4d8ef 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2290,6 +2290,7 @@
             android:exported="true">
             <intent-filter>
                 <action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
+                <action android:name="android.bluetooth.action.CSIS_SET_MEMBER_AVAILABLE"/>
             </intent-filter>
         </receiver>
 
diff --git a/res/layout/bluetooth_pin_confirm.xml b/res/layout/bluetooth_pin_confirm.xml
index 4891275..28ad1f6 100644
--- a/res/layout/bluetooth_pin_confirm.xml
+++ b/res/layout/bluetooth_pin_confirm.xml
@@ -65,6 +65,18 @@
             android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Subhead"
             android:visibility="gone" />
 
+        <TextView
+            android:id="@+id/pairing_group_message"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_marginStart="@dimen/bluetooth_dialog_padding"
+            android:layout_marginEnd="@dimen/bluetooth_dialog_padding"
+            android:layout_marginBottom="@dimen/bluetooth_dialog_padding"
+            android:gravity="center_vertical"
+            android:text="@string/bluetooth_paring_group_msg"
+            android:textAppearance="@*android:style/TextAppearance.DeviceDefault.Body1"
+            android:visibility="gone" />
+
         <CheckBox
             android:id="@+id/phonebook_sharing_message_confirm_pin"
             android:layout_width="wrap_content"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aec90e1..86c80c3 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1832,6 +1832,9 @@
     <!-- Message for confirmation of passkey to complete pairing. [CHAR LIMIT=NONE] -->
     <string name="bluetooth_confirm_passkey_msg">To pair with:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Make sure it is showing this passkey:&lt;br>&lt;b><xliff:g id="passkey">%2$s</xliff:g>&lt;/b></string>
 
+    <!-- Pairing dialog text to remind user the pairing including all of the devices in a coordinated set. [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_paring_group_msg">Confirm to pair with the coordinated set</string>
+
     <!-- Message when bluetooth incoming pairing request for (2.1 devices) dialog is showing -->
     <string name="bluetooth_incoming_pairing_msg">From:&lt;br>&lt;b><xliff:g id="device_name">%1$s</xliff:g>&lt;/b>&lt;br>&lt;br>Pair with this device?</string>
 
@@ -1909,6 +1912,8 @@
     <string name="device_details_title">Device details</string>
     <!-- Title of the item to show device MAC address -->
     <string name="bluetooth_device_mac_address">Device\'s Bluetooth address: <xliff:g id="address">%1$s</xliff:g></string>
+    <!-- Title of the items to show multuple devices MAC address [CHAR LIMIT=NONE]-->
+    <string name="bluetooth_multuple_devices_mac_address">Device\'s Bluetooth address:\n<xliff:g id="address">%1$s</xliff:g></string>
     <!-- Bluetooth device details. The title of a confirmation dialog for unpairing a paired device. [CHAR LIMIT=60] -->
     <string name="bluetooth_unpair_dialog_title">Forget device?</string>
     <!-- Content Description for companion device app associations removal button [CHAR LIMIT=28]-->
diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
index 27d63bf..14c20f1 100644
--- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java
@@ -70,9 +70,10 @@
             if (DBG) {
                 Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
             }
-            // If device is Hearing Aid, it is compatible with HFP and A2DP.
+            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
             // It would show in Available Devices group.
-            if (cachedDevice.isConnectedHearingAidDevice()) {
+            if (cachedDevice.isConnectedHearingAidDevice()
+                    || cachedDevice.isConnectedLeAudioDevice()) {
                 return true;
             }
             // According to the current audio profile type,
diff --git a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
index dda247e..c5f8453 100644
--- a/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
+++ b/src/com/android/settings/bluetooth/BluetoothDetailsMacAddressController.java
@@ -16,6 +16,7 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.content.Context;
 
 import androidx.preference.PreferenceFragmentCompat;
@@ -50,8 +51,17 @@
 
     @Override
     protected void refresh() {
-        mFooterPreference.setTitle(mContext.getString(
+        if (mCachedDevice.getGroupId() != BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+            StringBuilder mTitle = new StringBuilder(mContext.getString(
+                R.string.bluetooth_multuple_devices_mac_address, mCachedDevice.getAddress()));
+            for (CachedBluetoothDevice member: mCachedDevice.getMemberDevice()) {
+                mTitle.append("\n").append(member.getAddress());
+            }
+            mFooterPreference.setTitle(mTitle);
+        } else {
+            mFooterPreference.setTitle(mContext.getString(
                 R.string.bluetooth_device_mac_address, mCachedDevice.getAddress()));
+        }
     }
 
     @Override
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingController.java b/src/com/android/settings/bluetooth/BluetoothPairingController.java
index ca3dda6..ec5c8dd 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingController.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingController.java
@@ -28,6 +28,7 @@
 
 import com.android.settings.R;
 import com.android.settings.bluetooth.BluetoothPairingDialogFragment.BluetoothPairingDialogListener;
+import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfile;
 
@@ -64,6 +65,7 @@
     private String mDeviceName;
     private LocalBluetoothProfile mPbapClientProfile;
     private boolean mPbapAllowed;
+    private boolean mIsCoordinatedSetMember;
 
     /**
      * Creates an instance of a BluetoothPairingController.
@@ -90,6 +92,10 @@
         mDeviceName = mBluetoothManager.getCachedDeviceManager().getName(mDevice);
         mPbapClientProfile = mBluetoothManager.getProfileManager().getPbapClientProfile();
         mPasskeyFormatted = formatKey(mPasskey);
+        final CachedBluetoothDevice cachedDevice =
+                mBluetoothManager.getCachedDeviceManager().findDevice(mDevice);
+        mIsCoordinatedSetMember = (cachedDevice != null)
+                ? cachedDevice.isCoordinatedSetMemberDevice() : false;
     }
 
     @Override
@@ -156,6 +162,15 @@
     }
 
     /**
+     * A method for querying if the bluetooth device is a LE coordinated set member device.
+     *
+     * @return - A boolean indicating if the device is a CSIP supported device.
+     */
+    public boolean isCoordinatedSetMemberDevice() {
+        return mIsCoordinatedSetMember;
+    }
+
+    /**
      * A method for querying if the bluetooth device has a profile already set up on this device.
      *
      * @return - A boolean indicating if the device has previous knowledge of a profile for this
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
index d38302d..9e36247 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingDialogFragment.java
@@ -344,6 +344,9 @@
             pairingViewContent.setVisibility(View.VISIBLE);
             pairingViewContent.setText(mPairingController.getPairingContent());
         }
+        final TextView messagePairingSet = (TextView) view.findViewById(R.id.pairing_group_message);
+        messagePairingSet.setVisibility(mPairingController.isCoordinatedSetMemberDevice()
+                ? View.VISIBLE : View.GONE);
         return view;
     }
 
diff --git a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
index 993f584..6b80256 100644
--- a/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
+++ b/src/com/android/settings/bluetooth/BluetoothPairingRequest.java
@@ -16,12 +16,16 @@
 
 package com.android.settings.bluetooth;
 
+import android.bluetooth.BluetoothCsipSetCoordinator;
 import android.bluetooth.BluetoothDevice;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.text.TextUtils;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
 
 /**
  * BluetoothPairingRequest is a receiver for any Bluetooth pairing request. It
@@ -34,36 +38,55 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         String action = intent.getAction();
-        if (action == null || !action.equals(BluetoothDevice.ACTION_PAIRING_REQUEST)) {
+        if (action == null) {
             return;
         }
 
-        PowerManager powerManager = context.getSystemService(PowerManager.class);
         BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-        int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
-                BluetoothDevice.ERROR);
-        String deviceAddress = device != null ? device.getAddress() : null;
-        String deviceName = device != null ? device.getName() : null;
-        boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground(
-                context, deviceAddress, deviceName);
+        final LocalBluetoothManager mBluetoothManager = Utils.getLocalBtManager(context);
+        if (TextUtils.equals(action, BluetoothDevice.ACTION_PAIRING_REQUEST)) {
+            PowerManager powerManager = context.getSystemService(PowerManager.class);
+            int pairingVariant = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT,
+                    BluetoothDevice.ERROR);
+            String deviceAddress = device != null ? device.getAddress() : null;
+            String deviceName = device != null ? device.getName() : null;
+            boolean shouldShowDialog = LocalBluetoothPreferences.shouldShowDialogInForeground(
+                    context, deviceAddress, deviceName);
 
-        // Skips consent pairing dialog if the device was recently associated with CDM
-        if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
-                && device.canBondWithoutDialog()) {
-            device.setPairingConfirmation(true);
-        } else if (powerManager.isInteractive() && shouldShowDialog) {
-            // Since the screen is on and the BT-related activity is in the foreground,
-            // just open the dialog
-            // convert broadcast intent into activity intent (same action string)
-            Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context, intent,
-                    BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
+            // Skips consent pairing dialog if the device was recently associated with CDM
+            if (pairingVariant == BluetoothDevice.PAIRING_VARIANT_CONSENT
+                    && (device.canBondWithoutDialog()
+                    || mBluetoothManager.getCachedDeviceManager().isOngoingPairByCsip(device))) {
+                device.setPairingConfirmation(true);
+            } else if (powerManager.isInteractive() && shouldShowDialog) {
+                // Since the screen is on and the BT-related activity is in the foreground,
+                // just open the dialog
+                // convert broadcast intent into activity intent (same action string)
+                Intent pairingIntent = BluetoothPairingService.getPairingDialogIntent(context,
+                        intent, BluetoothDevice.EXTRA_PAIRING_INITIATOR_FOREGROUND);
 
-            context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
-        } else {
-            // Put up a notification that leads to the dialog
-            intent.setClass(context, BluetoothPairingService.class);
-            intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
-            context.startServiceAsUser(intent, UserHandle.CURRENT);
+                context.startActivityAsUser(pairingIntent, UserHandle.CURRENT);
+            } else {
+                // Put up a notification that leads to the dialog
+                intent.setClass(context, BluetoothPairingService.class);
+                intent.setAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
+                context.startServiceAsUser(intent, UserHandle.CURRENT);
+            }
+        } else if (TextUtils.equals(action,
+                BluetoothCsipSetCoordinator.ACTION_CSIS_SET_MEMBER_AVAILABLE)) {
+            if (device == null) {
+                return;
+            }
+
+            final int groupId = intent.getIntExtra(BluetoothCsipSetCoordinator.EXTRA_CSIS_GROUP_ID,
+                    BluetoothCsipSetCoordinator.GROUP_ID_INVALID);
+            if (groupId == BluetoothCsipSetCoordinator.GROUP_ID_INVALID) {
+                return;
+            }
+
+            if (mBluetoothManager.getCachedDeviceManager().shouldPairByCsip(device, groupId)) {
+                device.createBond(BluetoothDevice.TRANSPORT_LE);
+            }
         }
     }
 }
diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
index fc1b9b7..d1c45b6 100644
--- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java
@@ -70,9 +70,10 @@
             if (DBG) {
                 Log.d(TAG, "isFilterMatched() current audio profile : " + currentAudioProfile);
             }
-            // If device is Hearing Aid, it is compatible with HFP and A2DP.
+            // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP.
             // It would not show in Connected Devices group.
-            if (cachedDevice.isConnectedHearingAidDevice()) {
+            if (cachedDevice.isConnectedHearingAidDevice()
+                    || cachedDevice.isConnectedLeAudioDevice()) {
                 return false;
             }
             // According to the current audio profile type,
diff --git a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
index dab4f23..f5bc279 100644
--- a/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
+++ b/src/com/android/settings/bluetooth/SavedBluetoothDeviceUpdater.java
@@ -65,7 +65,7 @@
             removePreferenceIfNecessary(bluetoothDevices, cachedManager);
             for (BluetoothDevice device : bluetoothDevices) {
                 final CachedBluetoothDevice cachedDevice = cachedManager.findDevice(device);
-                if (cachedDevice != null) {
+                if (cachedDevice != null && !cachedManager.isSubDevice(device)) {
                     update(cachedDevice);
                 }
             }
diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
index 924e246..013ef52 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java
@@ -235,6 +235,32 @@
     }
 
     @Test
+    public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_addPreference() {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_addPreference() {
+        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice);
+    }
+
+    @Test
     public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP);
diff --git a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
index be733ec..a53e693 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/BluetoothPairingDialogTest.java
@@ -427,6 +427,34 @@
         userEntryDialogExistingTextTest("test");
     }
 
+    @Test
+    public void groupPairing_setMemberDevice_showsMessageHint() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
+        when(controller.isCoordinatedSetMemberDevice()).thenReturn(true);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify message is what we expect it to be and is visible
+        TextView message = frag.getmDialog().findViewById(R.id.pairing_group_message);
+        assertThat(message.getVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void groupPairing_nonSetMemberDevice_hidesMessageHint() {
+        // set the correct dialog type
+        when(controller.getDialogType()).thenReturn(BluetoothPairingController.CONFIRMATION_DIALOG);
+        when(controller.isCoordinatedSetMemberDevice()).thenReturn(false);
+
+        // build the fragment
+        BluetoothPairingDialogFragment frag = makeFragment();
+
+        // verify message is what we expect it to be and is visible
+        TextView message = frag.getmDialog().findViewById(R.id.pairing_group_message);
+        assertThat(message.getVisibility()).isEqualTo(View.GONE);
+    }
+
     // Runs a test simulating the user entry dialog type in a situation like device rotation, where
     // the dialog fragment gets created and we already have some existing text entered into the
     // pin field.
diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
index ea91fed..40b20dc 100644
--- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
+++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java
@@ -235,6 +235,33 @@
     }
 
     @Test
+    public void onProfileConnectionStateChanged_leAudioDeviceConnected_inCall_removePreference() {
+        mAudioManager.setMode(AudioManager.MODE_IN_CALL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
+    public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removePreference()
+    {
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        when(mBluetoothDeviceUpdater
+                .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true);
+        when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true);
+
+        mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
+                BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO);
+
+        verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice);
+    }
+
+    @Test
     public void onProfileConnectionStateChanged_deviceDisconnected_removePreference() {
         mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice,
                 BluetoothProfile.STATE_DISCONNECTED, BluetoothProfile.A2DP);