Update output switcher behavior and UI design

- Remove media stream stuff, use active device info as header.
- Show the sub title of media device.
- Add new requirement, when user click disconnected bluetooth device,
  will auto connceted it.
- When bluetooth state is off, do not showing content of slice.

Bug: 127201385
Test: make -j42 RunSettingsRoboTests
Change-Id: Ie1880ba3ef9910a42caf0cca2b6502e54787f5a0
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index 7416018..d1e55e4 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -70,7 +70,7 @@
 
     @Override
     public void close() {
-
+        mLocalMediaManager = null;
     }
 
     @Override
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index d52b441..232986c 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -20,13 +20,11 @@
 
 import android.annotation.ColorInt;
 import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -58,37 +56,48 @@
 
     private MediaDeviceUpdateWorker mWorker;
     private String mPackageName;
-    private IconDrawableFactory mIconDrawableFactory;
 
     public MediaOutputSlice(Context context) {
         mContext = context;
         mPackageName = getUri().getQueryParameter(MEDIA_PACKAGE_NAME);
-        mIconDrawableFactory = IconDrawableFactory.newInstance(mContext);
     }
 
     @VisibleForTesting
-    void init(String packageName, MediaDeviceUpdateWorker worker, IconDrawableFactory factory) {
+    void init(String packageName, MediaDeviceUpdateWorker worker) {
         mPackageName = packageName;
         mWorker = worker;
-        mIconDrawableFactory = factory;
     }
 
     @Override
     public Slice getSlice() {
-        final PackageManager pm = mContext.getPackageManager();
+        final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        if (!adapter.isEnabled()) {
+            Log.d(TAG, "getSlice() Bluetooth is off");
+            return null;
+        }
 
         final List<MediaDevice> devices = getMediaDevices();
-        final CharSequence title = Utils.getApplicationLabel(mContext, mPackageName);
-        final CharSequence summary =
-                mContext.getString(R.string.media_output_panel_summary_of_playing_device,
-                        getConnectedDeviceName());
-
-        final Drawable drawable =
-                Utils.getBadgedIcon(mIconDrawableFactory, pm, mPackageName, UserHandle.myUserId());
-        final IconCompat icon = Utils.createIconWithDrawable(drawable);
-
         @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
-        final SliceAction primarySliceAction = SliceAction.createDeeplink(getPrimaryAction(), icon,
+
+        final MediaDevice connectedDevice = getWorker().getCurrentConnectedMediaDevice();
+        final ListBuilder listBuilder = buildActiveDeviceHeader(color, connectedDevice);
+
+        for (MediaDevice device : devices) {
+            if (!TextUtils.equals(connectedDevice.getId(), device.getId())) {
+                listBuilder.addRow(getMediaDeviceRow(device));
+            }
+        }
+
+        return listBuilder.build();
+    }
+
+    private ListBuilder buildActiveDeviceHeader(@ColorInt int color, MediaDevice device) {
+        final String title = device.getName();
+        final IconCompat icon = IconCompat.createWithResource(mContext, device.getIcon());
+
+        final PendingIntent broadcastAction =
+                getBroadcastIntent(mContext, device.getId(), device.hashCode());
+        final SliceAction primarySliceAction = SliceAction.createDeeplink(broadcastAction, icon,
                 ListBuilder.ICON_IMAGE, title);
 
         final ListBuilder listBuilder = new ListBuilder(mContext, MEDIA_OUTPUT_SLICE_URI,
@@ -97,14 +106,10 @@
                 .addRow(new ListBuilder.RowBuilder()
                         .setTitleItem(icon, ListBuilder.ICON_IMAGE)
                         .setTitle(title)
-                        .setSubtitle(summary)
+                        .setSubtitle(device.getSummary())
                         .setPrimaryAction(primarySliceAction));
 
-        for (MediaDevice device : devices) {
-            listBuilder.addRow(getMediaDeviceRow(device));
-        }
-
-        return listBuilder.build();
+        return listBuilder;
     }
 
     private MediaDeviceUpdateWorker getWorker() {
@@ -120,18 +125,6 @@
         return devices;
     }
 
-    private String getConnectedDeviceName() {
-        final MediaDevice device = getWorker().getCurrentConnectedMediaDevice();
-        return device != null ? device.getName() : "";
-    }
-
-    private PendingIntent getPrimaryAction() {
-        final PackageManager pm = mContext.getPackageManager();
-        final Intent launchIntent = pm.getLaunchIntentForPackage(mPackageName);
-        final Intent intent = launchIntent;
-        return PendingIntent.getActivity(mContext, 0  /* requestCode */, intent, 0  /* flags */);
-    }
-
     private ListBuilder.RowBuilder getMediaDeviceRow(MediaDevice device) {
         final String title = device.getName();
         final PendingIntent broadcastAction =
@@ -141,7 +134,8 @@
                 .setTitleItem(deviceIcon, ListBuilder.ICON_IMAGE)
                 .setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
                         ListBuilder.ICON_IMAGE, title))
-                .setTitle(title);
+                .setTitle(title)
+                .setSubtitle(device.getSummary());
 
         return rowBuilder;
     }
diff --git a/src/com/android/settings/panel/SettingsPanelActivity.java b/src/com/android/settings/panel/SettingsPanelActivity.java
index 3819c80..8aee382 100644
--- a/src/com/android/settings/panel/SettingsPanelActivity.java
+++ b/src/com/android/settings/panel/SettingsPanelActivity.java
@@ -16,13 +16,11 @@
 
 package com.android.settings.panel;
 
-import static com.android.settingslib.media.MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT;
 import static com.android.settingslib.media.MediaOutputSliceConstants.EXTRA_PACKAGE_NAME;
 
 import android.app.settings.SettingsEnums;
 import android.content.Intent;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.MotionEvent;
@@ -75,15 +73,8 @@
             return;
         }
 
-        final String mediaPackageName =
-                callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
-
-        if (TextUtils.equals(ACTION_MEDIA_OUTPUT, callingIntent.getAction())
-                && TextUtils.isEmpty(mediaPackageName)) {
-            Log.e(TAG, "Missing EXTRA_PACKAGE_NAME, closing Panel Activity");
-            finish();
-            return;
-        }
+        // We will use it once media output switch panel support remote device.
+        final String mediaPackageName = callingIntent.getStringExtra(EXTRA_PACKAGE_NAME);
 
         setContentView(R.layout.settings_panel);
 
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
index daaba90..da0d85b 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
@@ -21,21 +21,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.bluetooth.BluetoothAdapter;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.UserHandle;
-import android.util.IconDrawableFactory;
 
 import androidx.slice.Slice;
 import androidx.slice.SliceMetadata;
@@ -43,6 +37,7 @@
 import androidx.slice.core.SliceAction;
 import androidx.slice.widget.SliceLiveData;
 
+import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 
@@ -53,70 +48,64 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
 
 import java.util.ArrayList;
 import java.util.List;
 
 @RunWith(RobolectricTestRunner.class)
+@Config(shadows = {ShadowBluetoothAdapter.class})
 public class MediaOutputSliceTest {
 
     private static final String TEST_PACKAGE_NAME = "com.fake.android.music";
-    private static final String TEST_LABEL = "Test app";
     private static final String TEST_DEVICE_1_ID = "test_device_1_id";
+    private static final String TEST_DEVICE_1_NAME = "test_device_1_name";
+    private static final int TEST_DEVICE_1_ICON =
+            com.android.internal.R.drawable.ic_bt_headphones_a2dp;
 
     @Mock
-    private PackageManager mPackageManager;
-    @Mock
-    private ApplicationInfo mApplicationInfo;
-    @Mock
-    private ApplicationInfo mApplicationInfo2;
-    @Mock
     private LocalMediaManager mLocalMediaManager;
-    @Mock
-    private IconDrawableFactory mIconDrawableFactory;
-    @Mock
-    private Drawable mTestDrawable;
 
     private final List<MediaDevice> mDevices = new ArrayList<>();
 
     private Context mContext;
     private MediaOutputSlice mMediaOutputSlice;
     private MediaDeviceUpdateWorker mMediaDeviceUpdateWorker;
+    private ShadowBluetoothAdapter mShadowBluetoothAdapter;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         mContext = spy(RuntimeEnvironment.application);
 
-        when(mContext.getPackageManager()).thenReturn(mPackageManager);
-        when(mPackageManager.getApplicationInfo(eq(TEST_PACKAGE_NAME), anyInt()))
-                .thenReturn(mApplicationInfo);
-        when(mPackageManager.getApplicationInfoAsUser(eq(TEST_PACKAGE_NAME), anyInt(), anyInt()))
-                .thenReturn(mApplicationInfo2);
-        when(mApplicationInfo.loadLabel(mPackageManager)).thenReturn(TEST_LABEL);
-        when(mIconDrawableFactory.getBadgedIcon(mApplicationInfo2, UserHandle.myUserId()))
-                .thenReturn(mTestDrawable);
-        when(mTestDrawable.getIntrinsicWidth()).thenReturn(100);
-        when(mTestDrawable.getIntrinsicHeight()).thenReturn(100);
-
         // Set-up specs for SliceMetadata.
         SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS);
+        // Setup BluetoothAdapter
+        mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter());
+        mShadowBluetoothAdapter.setEnabled(true);
 
         mMediaOutputSlice = new MediaOutputSlice(mContext);
         mMediaDeviceUpdateWorker = new MediaDeviceUpdateWorker(mContext, MEDIA_OUTPUT_SLICE_URI);
         mMediaDeviceUpdateWorker.setPackageName(TEST_PACKAGE_NAME);
         mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
         mMediaDeviceUpdateWorker.mLocalMediaManager = mLocalMediaManager;
-        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker, mIconDrawableFactory);
+        mMediaOutputSlice.init(TEST_PACKAGE_NAME, mMediaDeviceUpdateWorker);
     }
 
     @Test
-    public void getSlice_shouldHaveAppTitle() {
+    public void getSlice_shouldHaveActiveDeviceName() {
+        mDevices.clear();
+        final MediaDevice device = mock(MediaDevice.class);
+        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
+        when(device.getIcon()).thenReturn(TEST_DEVICE_1_ICON);
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);
+
         final Slice mediaSlice = mMediaOutputSlice.getSlice();
         final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice);
 
         final SliceAction primaryAction = metadata.getPrimaryAction();
-        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_LABEL);
+        assertThat(primaryAction.getTitle().toString()).isEqualTo(TEST_DEVICE_1_NAME);
     }
 
     @Test
diff --git a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
index a51b7b0..1d5c3c2 100644
--- a/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
+++ b/tests/robotests/src/com/android/settings/panel/SettingsPanelActivityTest.java
@@ -76,15 +76,16 @@
     }
 
     @Test
-    public void startMediaOutputSlice_withoutPackageName_bundleShouldNotHaveValue() {
+    public void startMediaOutputSlice_withoutPackageName_bundleShouldHaveValue() {
         final Intent intent = new Intent()
                 .setAction("com.android.settings.panel.action.MEDIA_OUTPUT");
 
         final SettingsPanelActivity activity =
                 Robolectric.buildActivity(SettingsPanelActivity.class, intent).create().get();
 
-        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isFalse();
-        assertThat(activity.mBundle.containsKey(KEY_PANEL_TYPE_ARGUMENT)).isFalse();
+        assertThat(activity.mBundle.containsKey(KEY_MEDIA_PACKAGE_NAME)).isTrue();
+        assertThat(activity.mBundle.getString(KEY_PANEL_TYPE_ARGUMENT))
+                .isEqualTo("com.android.settings.panel.action.MEDIA_OUTPUT");
     }
 
     @Test