Update rule of launching media output dialog

-Do not hide Media Output Dialog in Settings, and let dialog handles
-Hide Media output slice panel when launching dialog

Bug: 155822415
Test: make -j50 RunSettingsRoboTests
Merged-In: I16732f625f100b259d6e53c85db40af0ec1652c5
Change-Id: I16732f625f100b259d6e53c85db40af0ec1652c5
diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
index 401a0a6..40ee05b 100644
--- a/src/com/android/settings/media/MediaOutputIndicatorSlice.java
+++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java
@@ -16,18 +16,15 @@
 
 package com.android.settings.media;
 
-import static android.app.PendingIntent.FLAG_UPDATE_CURRENT;
-
 import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI;
 
 import android.annotation.ColorInt;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.media.session.MediaController;
 import android.net.Uri;
-import android.text.TextUtils;
+import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
 import androidx.core.graphics.drawable.IconCompat;
@@ -63,13 +60,8 @@
                 com.android.internal.R.drawable.ic_settings_bluetooth);
         final CharSequence title = mContext.getString(R.string.media_output_label_title,
                 Utils.getApplicationLabel(mContext, getWorker().getPackageName()));
-        final int requestCode = TextUtils.isEmpty(getWorker().getPackageName())
-                ? 0
-                : getWorker().getPackageName().hashCode();
-        final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext,
-                requestCode, getMediaOutputDialogIntent(), FLAG_UPDATE_CURRENT);
-        final SliceAction primarySliceAction = SliceAction.createDeeplink(
-                primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE, title);
+        final SliceAction primarySliceAction = SliceAction.create(
+                getBroadcastIntent(mContext), icon, ListBuilder.ICON_IMAGE, title);
 
         @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext);
         // To set an empty icon to indent the row
@@ -83,21 +75,6 @@
         return listBuilder.build();
     }
 
-    @VisibleForTesting
-    Intent getMediaOutputDialogIntent() {
-        final MediaController mediaController = getWorker().getActiveLocalMediaController();
-        final Intent intent = new Intent()
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG);
-        if (mediaController != null) {
-            intent.putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN,
-                    mediaController.getSessionToken());
-            intent.putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
-                    mediaController.getPackageName());
-        }
-        return intent;
-    }
-
     private IconCompat createEmptyIcon() {
         final Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
         return IconCompat.createWithBitmap(bitmap);
@@ -140,4 +117,26 @@
                 && getWorker().getMediaDevices().size() > 0
                 && getWorker().getActiveLocalMediaController() != null;
     }
+
+    @Override
+    public void onNotifyChange(Intent intent) {
+        final MediaController mediaController = getWorker().getActiveLocalMediaController();
+
+        if (mediaController == null) {
+            Log.d(TAG, "No active local media controller");
+            return;
+        }
+        // Launch media output dialog
+        mContext.sendBroadcast(new Intent()
+                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
+                .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                .putExtra(MediaOutputSliceConstants.KEY_MEDIA_SESSION_TOKEN,
+                        mediaController.getSessionToken())
+                .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                        mediaController.getPackageName()));
+        // Dismiss volume panel
+        mContext.sendBroadcast(new Intent()
+                .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME)
+                .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL));
+    }
 }
diff --git a/src/com/android/settings/media/RemoteMediaSlice.java b/src/com/android/settings/media/RemoteMediaSlice.java
index 1ca33b1..5e50b55 100644
--- a/src/com/android/settings/media/RemoteMediaSlice.java
+++ b/src/com/android/settings/media/RemoteMediaSlice.java
@@ -59,6 +59,9 @@
 
     private static final String TAG = "RemoteMediaSlice";
     private static final String MEDIA_ID = "media_id";
+    private static final String ACTION_LAUNCH_DIALOG = "action_launch_dialog";
+    private static final String SESSION_INFO = "RoutingSessionInfo";
+    private static final String CUSTOMIZED_ACTION = "customized_action";
 
     private final Context mContext;
 
@@ -77,6 +80,20 @@
         final String id = intent.getStringExtra(MEDIA_ID);
         if (!TextUtils.isEmpty(id)) {
             getWorker().adjustSessionVolume(id, newPosition);
+            return;
+        }
+        if (TextUtils.equals(ACTION_LAUNCH_DIALOG, intent.getStringExtra(CUSTOMIZED_ACTION))) {
+            // Launch Media Output Dialog
+            final RoutingSessionInfo info = intent.getParcelableExtra(SESSION_INFO);
+            mContext.sendBroadcast(new Intent()
+                    .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
+                    .setAction(MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
+                    .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
+                            info.getClientPackageName()));
+            // Dismiss volume panel
+            mContext.sendBroadcast(new Intent()
+                    .setPackage(MediaOutputSliceConstants.SETTINGS_PACKAGE_NAME)
+                    .setAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL));
         }
     }
 
@@ -168,19 +185,18 @@
 
     private SliceAction getMediaOutputDialogAction(RoutingSessionInfo info,
             boolean isMediaOutputDisabled) {
-        final Intent intent = new Intent()
-                .setAction(isMediaOutputDisabled
-                        ? "" : MediaOutputSliceConstants.ACTION_LAUNCH_MEDIA_OUTPUT_DIALOG)
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME)
-                .putExtra(MediaOutputSliceConstants.EXTRA_PACKAGE_NAME,
-                        info.getClientPackageName());
-        final IconCompat icon = IconCompat.createWithResource(mContext,
-                R.drawable.ic_volume_remote);
-
+        final Intent intent = new Intent(getUri().toString())
+                .setData(getUri())
+                .setClass(mContext, SliceBroadcastReceiver.class)
+                .putExtra(CUSTOMIZED_ACTION, isMediaOutputDisabled ? "" : ACTION_LAUNCH_DIALOG)
+                .putExtra(SESSION_INFO, info)
+                .addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         final PendingIntent primaryBroadcastIntent = PendingIntent.getBroadcast(mContext,
-                0 /* requestCode */, intent, 0 /* flags */);
+                info.hashCode(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
         final SliceAction primarySliceAction = SliceAction.createDeeplink(
-                primaryBroadcastIntent, icon, ListBuilder.ICON_IMAGE,
+                primaryBroadcastIntent,
+                IconCompat.createWithResource(mContext, R.drawable.ic_volume_remote),
+                ListBuilder.ICON_IMAGE,
                 mContext.getString(R.string.media_output_label_title,
                         Utils.getApplicationLabel(mContext, info.getClientPackageName())));
         return primarySliceAction;
diff --git a/src/com/android/settings/notification/RemoteVolumeGroupController.java b/src/com/android/settings/notification/RemoteVolumeGroupController.java
index 4dd497f..eb72c59 100644
--- a/src/com/android/settings/notification/RemoteVolumeGroupController.java
+++ b/src/com/android/settings/notification/RemoteVolumeGroupController.java
@@ -32,7 +32,6 @@
 import com.android.settings.core.BasePreferenceController;
 import com.android.settingslib.core.lifecycle.LifecycleObserver;
 import com.android.settingslib.core.lifecycle.events.OnDestroy;
-import com.android.settingslib.core.lifecycle.events.OnPause;
 import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
@@ -46,7 +45,7 @@
  * {@link com.android.settings.notification.RemoteVolumeSeekBarPreference}
  **/
 public class RemoteVolumeGroupController extends BasePreferenceController implements
-        Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy, OnPause,
+        Preference.OnPreferenceChangeListener, LifecycleObserver, OnDestroy,
         LocalMediaManager.DeviceCallback {
 
     private static final String KEY_REMOTE_VOLUME_GROUP = "remote_media_group";
@@ -98,14 +97,6 @@
     }
 
     @Override
-    public void onPause() {
-        // Media output dialog should not show when onPause
-        mContext.sendBroadcast(new Intent()
-                .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG)
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME));
-    }
-
-    @Override
     public void onDestroy() {
         mLocalMediaManager.unregisterCallback(this);
         mLocalMediaManager.stopScan();
diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java
index 7c34a7c..b5e807d 100644
--- a/src/com/android/settings/panel/VolumePanel.java
+++ b/src/com/android/settings/panel/VolumePanel.java
@@ -17,6 +17,7 @@
 package com.android.settings.panel;
 
 import static androidx.lifecycle.Lifecycle.Event.ON_PAUSE;
+import static androidx.lifecycle.Lifecycle.Event.ON_RESUME;
 
 import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI;
 import static com.android.settings.slices.CustomSliceRegistry.REMOTE_MEDIA_SLICE_URI;
@@ -26,8 +27,10 @@
 import static com.android.settings.slices.CustomSliceRegistry.VOLUME_RINGER_URI;
 
 import android.app.settings.SettingsEnums;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.net.Uri;
 import android.provider.Settings;
 
@@ -47,6 +50,17 @@
 
     private final Context mContext;
 
+    private PanelContentCallback mCallback;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (MediaOutputSliceConstants.ACTION_CLOSE_PANEL.equals(intent.getAction())) {
+                mCallback.forceClose();
+            }
+        }
+    };
+
     public static VolumePanel create(Context context) {
         return new VolumePanel(context);
     }
@@ -55,13 +69,18 @@
         mContext = context.getApplicationContext();
     }
 
+    /** Invoked when the panel is resumed. */
+    @OnLifecycleEvent(ON_RESUME)
+    public void onResume() {
+        final IntentFilter filter = new IntentFilter();
+        filter.addAction(MediaOutputSliceConstants.ACTION_CLOSE_PANEL);
+        mContext.registerReceiver(mReceiver, filter);
+    }
+
     /** Invoked when the panel is paused. */
     @OnLifecycleEvent(ON_PAUSE)
     public void onPause() {
-        // Media output dialog should not show when onPause
-        mContext.sendBroadcast(new Intent()
-                .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG)
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME));
+        mContext.unregisterReceiver(mReceiver);
     }
 
     @Override
@@ -96,4 +115,9 @@
     public int getViewType() {
         return PanelContent.VIEW_TYPE_SLIDER;
     }
+
+    @Override
+    public void registerCallback(PanelContentCallback callback) {
+        mCallback = callback;
+    }
 }
\ No newline at end of file
diff --git a/src/com/android/settings/sound/MediaOutputPreferenceController.java b/src/com/android/settings/sound/MediaOutputPreferenceController.java
index 914a9de..7c3d2b1 100644
--- a/src/com/android/settings/sound/MediaOutputPreferenceController.java
+++ b/src/com/android/settings/sound/MediaOutputPreferenceController.java
@@ -33,8 +33,6 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
-import com.android.settingslib.core.lifecycle.LifecycleObserver;
-import com.android.settingslib.core.lifecycle.events.OnStop;
 import com.android.settingslib.media.MediaOutputSliceConstants;
 
 import java.util.List;
@@ -47,8 +45,7 @@
  * - Media stream captured by remote device
  * - During a call.
  */
-public class MediaOutputPreferenceController extends AudioSwitchPreferenceController
-        implements LifecycleObserver, OnStop {
+public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
 
     private MediaController mMediaController;
 
@@ -67,15 +64,6 @@
     }
 
     @Override
-    public void onStop() {
-        super.onStop();
-        // Media output dialog should not show when onStop
-        mContext.sendBroadcast(new Intent()
-                .setAction(MediaOutputSliceConstants.ACTION_DISMISS_MEDIA_OUTPUT_DIALOG)
-                .setPackage(MediaOutputSliceConstants.SYSTEMUI_PACKAGE_NAME));
-    }
-
-    @Override
     public void updateState(Preference preference) {
         if (preference == null) {
             // In case UI is not ready.
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
index 21ab883..68848af 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java
@@ -23,6 +23,8 @@
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -54,6 +56,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -203,12 +206,17 @@
     }
 
     @Test
-    public void getMediaOutputSliceIntent_withActiveLocalMedia_verifyIntentExtra() {
+    public void onNotifyChange_withActiveLocalMedia_verifyIntentExtra() {
         when(mMediaController.getSessionToken()).thenReturn(mToken);
         when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
         doReturn(mMediaController).when(sMediaOutputIndicatorWorker)
                 .getActiveLocalMediaController();
-        final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent();
+        ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
+
+        mMediaOutputIndicatorSlice.onNotifyChange(null);
+        verify(mContext, times(2)).sendBroadcast(argument.capture());
+        List<Intent> intentList = argument.getAllValues();
+        Intent intent = intentList.get(0);
 
         assertThat(TextUtils.equals(TEST_PACKAGE_NAME, intent.getStringExtra(
                 MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue();
@@ -221,10 +229,15 @@
     }
 
     @Test
-    public void getMediaOutputSliceIntent_withoutActiveLocalMedia_verifyIntentExtra() {
+    public void onNotifyChange_withoutActiveLocalMedia_verifyIntentExtra() {
         doReturn(mMediaController).when(sMediaOutputIndicatorWorker)
                 .getActiveLocalMediaController();
-        final Intent intent = mMediaOutputIndicatorSlice.getMediaOutputDialogIntent();
+        ArgumentCaptor<Intent> argument = ArgumentCaptor.forClass(Intent.class);
+
+        mMediaOutputIndicatorSlice.onNotifyChange(null);
+        verify(mContext, times(2)).sendBroadcast(argument.capture());
+        List<Intent> intentList = argument.getAllValues();
+        Intent intent = intentList.get(0);
 
         assertThat(TextUtils.isEmpty(intent.getStringExtra(
                 MediaOutputSliceConstants.EXTRA_PACKAGE_NAME))).isTrue();