Merge "Support Bluetooth activation in BluetoothDevicesSlice"
diff --git a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
index ad8d4a6..f8b7fe45 100644
--- a/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
+++ b/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSlice.java
@@ -46,6 +46,7 @@
 import com.android.settings.core.SubSettingLauncher;
 import com.android.settings.slices.CustomSliceRegistry;
 import com.android.settings.slices.CustomSliceable;
+import com.android.settings.slices.SliceBroadcastReceiver;
 import com.android.settings.slices.SliceBuilderUtils;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -59,10 +60,12 @@
 
 public class BluetoothDevicesSlice implements CustomSliceable {
 
+    @VisibleForTesting
+    static final String BLUETOOTH_DEVICE_HASH_CODE = "bluetooth_device_hash_code";
+
     /**
-     * TODO(b/114807655): Contextual Home Page - Connected Device
-     * Re-design sorting for new rule:
-     * Sorting rule: Audio Streaming > Last connected > Recently connected.
+     * Refer {@link com.android.settings.bluetooth.BluetoothDevicePreference#compareTo} to sort the
+     * Bluetooth devices by {@link CachedBluetoothDevice}.
      */
     private static final Comparator<CachedBluetoothDevice> COMPARATOR
             = Comparator.naturalOrder();
@@ -109,12 +112,11 @@
         final SliceAction primarySliceAction = SliceAction.createDeeplink(primaryActionIntent, icon,
                 ListBuilder.ICON_IMAGE, title);
         final ListBuilder listBuilder =
-                new ListBuilder(mContext, CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI,
-                        ListBuilder.INFINITY)
+                new ListBuilder(mContext, getUri(), ListBuilder.INFINITY)
                         .setAccentColor(Utils.getColorAccentDefaultColor(mContext));
 
         // Get row builders by Bluetooth devices.
-        final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder(primarySliceAction);
+        final List<ListBuilder.RowBuilder> rows = getBluetoothRowBuilder();
 
         // Return a header with IsError flag, if no Bluetooth devices.
         if (rows.isEmpty()) {
@@ -131,7 +133,7 @@
                 .setSubtitle(getSubTitle(rows.size()))
                 .setPrimaryAction(primarySliceAction));
 
-        // Add bluetooth device rows.
+        // Add Bluetooth device rows.
         for (ListBuilder.RowBuilder rowBuilder : rows) {
             listBuilder.addRow(rowBuilder);
         }
@@ -154,11 +156,19 @@
                 screenTitle,
                 MetricsProto.MetricsEvent.SLICE)
                 .setClassName(mContext.getPackageName(), SubSettings.class.getName())
-                .setData(CustomSliceRegistry.BLUETOOTH_DEVICES_SLICE_URI);
+                .setData(getUri());
     }
 
     @Override
     public void onNotifyChange(Intent intent) {
+        // Activate available media device.
+        final int bluetoothDeviceHashCode = intent.getIntExtra(BLUETOOTH_DEVICE_HASH_CODE, -1);
+        for (CachedBluetoothDevice cachedBluetoothDevice : getConnectedBluetoothDevices()) {
+            if (cachedBluetoothDevice.hashCode() == bluetoothDeviceHashCode) {
+                cachedBluetoothDevice.setActive();
+                return;
+            }
+        }
     }
 
     @Override
@@ -167,10 +177,10 @@
     }
 
     @VisibleForTesting
-    List<CachedBluetoothDevice> getBluetoothDevices() {
+    List<CachedBluetoothDevice> getConnectedBluetoothDevices() {
         final List<CachedBluetoothDevice> bluetoothDeviceList = new ArrayList<>();
 
-        // If Bluetooth is disable, skip to get the bluetooth devices.
+        // If Bluetooth is disable, skip to get the Bluetooth devices.
         if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
             Log.i(TAG, "Cannot get Bluetooth devices, Bluetooth is disabled.");
             return bluetoothDeviceList;
@@ -188,12 +198,13 @@
 
         /**
          * TODO(b/114807655): Contextual Home Page - Connected Device
-         * Re-design to get all Bluetooth devices and sort them by new rule:
-         * Sorting rule: Audio Streaming > Last connected > Recently connected.
+         * It's under discussion for including available media devices and currently connected
+         * devices from Bluetooth. Will update the devices list or remove TODO later.
          */
-        // Get connected Bluetooth devices and sort them.
-        return cachedDevices.stream().filter(device -> device.isConnected()).sorted(
-                COMPARATOR).collect(Collectors.toList());
+        // Get available media device list and sort them.
+        return cachedDevices.stream()
+                .filter(device -> device.isConnected() && device.isConnectedA2dpDevice())
+                .sorted(COMPARATOR).collect(Collectors.toList());
     }
 
     @VisibleForTesting
@@ -226,27 +237,35 @@
         }
     }
 
-    private List<ListBuilder.RowBuilder> getBluetoothRowBuilder(SliceAction primarySliceAction) {
+    private List<ListBuilder.RowBuilder> getBluetoothRowBuilder() {
+        // According Bluetooth devices to create row builders.
         final List<ListBuilder.RowBuilder> bluetoothRows = new ArrayList<>();
-
-        /**
-         * TODO(b/114807655): Contextual Home Page - Connected Device
-         * Re-design to do action "activating" in primary action.
-         */
-        // According Bluetooth device to create row builders.
-        final List<CachedBluetoothDevice> bluetoothDevices = getBluetoothDevices();
+        final List<CachedBluetoothDevice> bluetoothDevices = getConnectedBluetoothDevices();
         for (CachedBluetoothDevice bluetoothDevice : bluetoothDevices) {
             bluetoothRows.add(new ListBuilder.RowBuilder()
                     .setTitleItem(getBluetoothDeviceIcon(bluetoothDevice), ListBuilder.ICON_IMAGE)
                     .setTitle(bluetoothDevice.getName())
                     .setSubtitle(bluetoothDevice.getConnectionSummary())
-                    .setPrimaryAction(primarySliceAction)
+                    .setPrimaryAction(buildBluetoothDeviceAction(bluetoothDevice))
                     .addEndItem(buildBluetoothDetailDeepLinkAction(bluetoothDevice)));
         }
 
         return bluetoothRows;
     }
 
+    private SliceAction buildBluetoothDeviceAction(CachedBluetoothDevice bluetoothDevice) {
+        // Send broadcast to activate available media device.
+        final Intent intent = new Intent(getUri().toString())
+                .setClass(mContext, SliceBroadcastReceiver.class)
+                .putExtra(BLUETOOTH_DEVICE_HASH_CODE, bluetoothDevice.hashCode());
+
+        return SliceAction.create(
+                PendingIntent.getBroadcast(mContext, bluetoothDevice.hashCode(), intent, 0),
+                getBluetoothDeviceIcon(bluetoothDevice),
+                ListBuilder.ICON_IMAGE,
+                bluetoothDevice.getName());
+    }
+
     private SliceAction buildBluetoothDetailDeepLinkAction(CachedBluetoothDevice bluetoothDevice) {
         return SliceAction.createDeeplink(
                 getBluetoothDetailIntent(bluetoothDevice),
diff --git a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
index 51e8cc8..ebdc5aa 100644
--- a/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
+++ b/tests/robotests/src/com/android/settings/homepage/contextualcards/slices/BluetoothDevicesSliceTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.PendingIntent;
@@ -54,6 +55,7 @@
 @RunWith(RobolectricTestRunner.class)
 public class BluetoothDevicesSliceTest {
 
+    private static final String BLUETOOTH_MOCK_ADDRESS = "00:11:00:11:00:11";
     private static final String BLUETOOTH_MOCK_SUMMARY = "BluetoothSummary";
     private static final String BLUETOOTH_MOCK_TITLE = "BluetoothTitle";
 
@@ -96,7 +98,7 @@
     @Test
     public void getSlice_hasBluetoothDevices_shouldHaveBluetoothDevicesTitle() {
         mockBluetoothDeviceList();
-        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
@@ -107,7 +109,7 @@
     @Test
     public void getSlice_hasBluetoothDevices_shouldMatchBluetoothMockTitle() {
         mockBluetoothDeviceList();
-        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
@@ -118,7 +120,7 @@
     @Test
     public void getSlice_hasBluetoothDevices_shouldHavePairNewDevice() {
         mockBluetoothDeviceList();
-        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
@@ -129,7 +131,7 @@
 
     @Test
     public void getSlice_noBluetoothDevices_shouldHaveNoBluetoothDevicesTitle() {
-        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
@@ -139,7 +141,7 @@
 
     @Test
     public void getSlice_noBluetoothDevices_shouldNotHavePairNewDevice() {
-        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getBluetoothDevices();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
 
         final Slice slice = mBluetoothDevicesSlice.getSlice();
 
@@ -148,9 +150,24 @@
                 mContext.getString(R.string.bluetooth_pairing_pref_title))).isFalse();
     }
 
+    @Test
+    public void onNotifyChange_mediaDevice_shouldActivateDevice() {
+        mockBluetoothDeviceList();
+        doReturn(mBluetoothDeviceList).when(mBluetoothDevicesSlice).getConnectedBluetoothDevices();
+        final Intent intent = new Intent().putExtra(
+                BluetoothDevicesSlice.BLUETOOTH_DEVICE_HASH_CODE,
+                mCachedBluetoothDevice.hashCode());
+
+        mBluetoothDevicesSlice.onNotifyChange(intent);
+
+        verify(mCachedBluetoothDevice).setActive();
+    }
+
     private void mockBluetoothDeviceList() {
         doReturn(BLUETOOTH_MOCK_TITLE).when(mCachedBluetoothDevice).getName();
         doReturn(BLUETOOTH_MOCK_SUMMARY).when(mCachedBluetoothDevice).getConnectionSummary();
+        doReturn(BLUETOOTH_MOCK_ADDRESS).when(mCachedBluetoothDevice).getAddress();
+        doReturn(true).when(mCachedBluetoothDevice).isConnectedA2dpDevice();
         mBluetoothDeviceList.add(mCachedBluetoothDevice);
     }