Add "Stop" button for remote device

-Add "Stop" to stop remote media session
-Refine UI layout
1. Adjust size of head icon and apply defined dimen value
2. Move list padding inside the list to prevent truncating the list
3. Remove group-related view(I will add it in recycle view when the group feature is ready.)
-Add MediaOutputDialogTest
-Rename PAIR_NEW to CUSTOMIZED_ITEM_PAIR_NEW
-Integrate more UI view in setTwoLineLayout()

Bug: 155822415
Test: atest MediaOutputAdapterTest MediaOutputBaseDialogTest MediaOutputControllerTest MediaOutputDialogTest
Merged-In: Ie6a917c56a0ef97f772a8f43742afd2ee61e407f
Change-Id: Ie6a917c56a0ef97f772a8f43742afd2ee61e407f
diff --git a/packages/SystemUI/res/layout/media_output_dialog.xml b/packages/SystemUI/res/layout/media_output_dialog.xml
index 0229e6e..73beefc 100644
--- a/packages/SystemUI/res/layout/media_output_dialog.xml
+++ b/packages/SystemUI/res/layout/media_output_dialog.xml
@@ -32,7 +32,7 @@
             android:id="@+id/header_icon"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:paddingEnd="16dp"/>
+            android:paddingEnd="@dimen/media_output_dialog_header_icon_padding"/>
 
         <LinearLayout
             android:layout_width="match_parent"
@@ -70,36 +70,14 @@
         android:id="@+id/device_list"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:gravity="start|center_vertical"
         android:orientation="vertical">
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="12dp"/>
-
-        <include
-            layout="@layout/media_output_list_item"
-            android:id="@+id/group_item_controller"
-            android:visibility="gone"/>
-
-        <View
-            android:id="@+id/group_item_divider"
-            android:layout_width="match_parent"
-            android:layout_height="1dp"
-            android:background="?android:attr/listDivider"
-            android:visibility="gone"/>
-
         <androidx.recyclerview.widget.RecyclerView
             android:id="@+id/list_result"
             android:scrollbars="vertical"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:overScrollMode="never"/>
-
-        <View
-            android:id="@+id/list_bottom_padding"
-            android:layout_width="match_parent"
-            android:layout_height="12dp"/>
     </LinearLayout>
 
     <View
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4cd8d19..a4f87f0 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1404,9 +1404,10 @@
     <dimen name="config_rounded_mask_size_bottom">@*android:dimen/rounded_corner_radius_bottom</dimen>
 
     <!-- Output switcher panel related dimensions -->
-    <dimen name="media_output_dialog_padding_top">11dp</dimen>
+    <dimen name="media_output_dialog_list_margin">12dp</dimen>
     <dimen name="media_output_dialog_list_max_height">364dp</dimen>
     <dimen name="media_output_dialog_header_album_icon_size">52dp</dimen>
     <dimen name="media_output_dialog_header_back_icon_size">36dp</dimen>
+    <dimen name="media_output_dialog_header_icon_padding">16dp</dimen>
     <dimen name="media_output_dialog_icon_corner_radius">16dp</dimen>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
index 9fc64d5..9b6a9ea 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapter.java
@@ -42,7 +42,7 @@
 public class MediaOutputAdapter extends MediaOutputBaseAdapter {
 
     private static final String TAG = "MediaOutputAdapter";
-    private static final int PAIR_NEW = 1;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     public MediaOutputAdapter(MediaOutputController controller) {
         super(controller);
@@ -58,11 +58,14 @@
 
     @Override
     public void onBindViewHolder(@NonNull MediaDeviceBaseViewHolder viewHolder, int position) {
-        if (mController.isZeroMode() && position == (mController.getMediaDevices().size())) {
-            viewHolder.onBind(PAIR_NEW);
-        } else if (position < (mController.getMediaDevices().size())) {
-            viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position));
-        } else {
+        final int size = mController.getMediaDevices().size();
+        if (mController.isZeroMode() && position == size) {
+            viewHolder.onBind(CUSTOMIZED_ITEM_PAIR_NEW, false /* topMargin */,
+                    true /* bottomMargin */);
+        } else if (position < size) {
+            viewHolder.onBind(((List<MediaDevice>) (mController.getMediaDevices())).get(position),
+                    position == 0 /* topMargin */, position == (size - 1) /* bottomMargin */);
+        } else if (DEBUG) {
             Log.d(TAG, "Incorrect position: " + position);
         }
     }
@@ -83,7 +86,7 @@
     }
 
     void onItemClick(int customizedItem) {
-        if (customizedItem == PAIR_NEW) {
+        if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
             mController.launchBluetoothPairing();
         }
     }
@@ -112,51 +115,49 @@
         }
 
         @Override
-        void onBind(MediaDevice device) {
-            super.onBind(device);
+        void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
+            super.onBind(device, topMargin, bottomMargin);
             if (mController.isTransferring()) {
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING
                         && !mController.hasAdjustVolumeUserRestriction()) {
-                    setTwoLineLayout(device, true);
-                    mProgressBar.setVisibility(View.VISIBLE);
-                    mSeekBar.setVisibility(View.GONE);
-                    mSubTitleText.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, true /* bFocused */,
+                            false /* showSeekBar*/, true /* showProgressBar */,
+                            false /* showSubtitle */);
                 } else {
-                    setSingleLineLayout(getItemTitle(device), false);
+                    setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                 }
             } else {
                 // Set different layout for each device
                 if (device.getState() == MediaDeviceState.STATE_CONNECTING_FAILED) {
-                    setTwoLineLayout(device, false);
-                    mSubTitleText.setVisibility(View.VISIBLE);
-                    mSeekBar.setVisibility(View.GONE);
-                    mProgressBar.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, false /* bFocused */,
+                            false /* showSeekBar*/, false /* showProgressBar */,
+                            true /* showSubtitle */);
                     mSubTitleText.setText(R.string.media_output_dialog_connect_failed);
                     mFrameLayout.setOnClickListener(v -> onItemClick(device));
                 } else if (!mController.hasAdjustVolumeUserRestriction()
                         && isCurrentConnected(device)) {
-                    setTwoLineLayout(device, true);
-                    mSeekBar.setVisibility(View.VISIBLE);
-                    mProgressBar.setVisibility(View.GONE);
-                    mSubTitleText.setVisibility(View.GONE);
+                    setTwoLineLayout(device, null /* title */, true /* bFocused */,
+                            true /* showSeekBar*/, false /* showProgressBar */,
+                            false /* showSubtitle */);
                     initSeekbar(device);
                 } else {
-                    setSingleLineLayout(getItemTitle(device), false);
+                    setSingleLineLayout(getItemTitle(device), false /* bFocused */);
                     mFrameLayout.setOnClickListener(v -> onItemClick(device));
                 }
             }
         }
 
         @Override
-        void onBind(int customizedItem) {
-            if (customizedItem == PAIR_NEW) {
+        void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+            super.onBind(customizedItem, topMargin, bottomMargin);
+            if (customizedItem == CUSTOMIZED_ITEM_PAIR_NEW) {
                 setSingleLineLayout(mContext.getText(R.string.media_output_dialog_pairing_new),
-                        false);
+                        false /* bFocused */);
                 final Drawable d = mContext.getDrawable(R.drawable.ic_add);
                 d.setColorFilter(new PorterDuffColorFilter(
                         Utils.getColorAccentDefaultColor(mContext), PorterDuff.Mode.SRC_IN));
                 mTitleIcon.setImageDrawable(d);
-                mFrameLayout.setOnClickListener(v -> onItemClick(PAIR_NEW));
+                mFrameLayout.setOnClickListener(v -> onItemClick(CUSTOMIZED_ITEM_PAIR_NEW));
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
index 7579c25..01dc6c4 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseAdapter.java
@@ -44,9 +44,12 @@
     private static final String FONT_SELECTED_TITLE = "sans-serif-medium";
     private static final String FONT_TITLE = "sans-serif";
 
+    static final int CUSTOMIZED_ITEM_PAIR_NEW = 1;
+
     final MediaOutputController mController;
 
     private boolean mIsDragging;
+    private int mMargin;
 
     Context mContext;
     View mHolderView;
@@ -60,6 +63,8 @@
     public MediaDeviceBaseViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup,
             int viewType) {
         mContext = viewGroup.getContext();
+        mMargin = mContext.getResources().getDimensionPixelSize(
+                R.dimen.media_output_dialog_list_margin);
         mHolderView = LayoutInflater.from(mContext).inflate(R.layout.media_output_list_item,
                 viewGroup, false);
 
@@ -106,12 +111,26 @@
             mSeekBar = view.requireViewById(R.id.volume_seekbar);
         }
 
-        void onBind(MediaDevice device) {
+        void onBind(MediaDevice device, boolean topMargin, boolean bottomMargin) {
             mTitleIcon.setImageIcon(mController.getDeviceIconCompat(device).toIcon(mContext));
+            setMargin(topMargin, bottomMargin);
         }
 
-        void onBind(int customizedItem) { }
+        void onBind(int customizedItem, boolean topMargin, boolean bottomMargin) {
+            setMargin(topMargin, bottomMargin);
+        }
 
+        private void setMargin(boolean topMargin, boolean bottomMargin) {
+            ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mFrameLayout
+                    .getLayoutParams();
+            if (topMargin) {
+                params.topMargin = mMargin;
+            }
+            if (bottomMargin) {
+                params.bottomMargin = mMargin;
+            }
+            mFrameLayout.setLayoutParams(params);
+        }
         void setSingleLineLayout(CharSequence title, boolean bFocused) {
             mTitleText.setVisibility(View.VISIBLE);
             mTwoLineLayout.setVisibility(View.GONE);
@@ -123,10 +142,19 @@
             }
         }
 
-        void setTwoLineLayout(MediaDevice device, boolean bFocused) {
+        void setTwoLineLayout(MediaDevice device, CharSequence title, boolean bFocused,
+                boolean showSeekBar, boolean showProgressBar, boolean showSubtitle) {
             mTitleText.setVisibility(View.GONE);
             mTwoLineLayout.setVisibility(View.VISIBLE);
-            mTwoLineTitleText.setText(getItemTitle(device));
+            mSeekBar.setVisibility(showSeekBar ? View.VISIBLE : View.GONE);
+            mProgressBar.setVisibility(showProgressBar ? View.VISIBLE : View.GONE);
+            mSubTitleText.setVisibility(showSubtitle ? View.VISIBLE : View.GONE);
+            if (device == null) {
+                mTwoLineTitleText.setText(title);
+            } else {
+                mTwoLineTitleText.setText(getItemTitle(device));
+            }
+
             if (bFocused) {
                 mTwoLineTitleText.setTypeface(Typeface.create(FONT_SELECTED_TITLE,
                         Typeface.NORMAL));
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
index 781bf8d..a589b07 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputBaseDialog.java
@@ -33,7 +33,6 @@
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.widget.Button;
-import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -69,12 +68,9 @@
     private LinearLayout mDeviceListLayout;
     private Button mDoneButton;
     private Button mStopButton;
-    private View mListBottomPadding;
     private int mListMaxHeight;
 
     MediaOutputBaseAdapter mAdapter;
-    FrameLayout mGroupItemController;
-    View mGroupDivider;
 
     private final ViewTreeObserver.OnGlobalLayoutListener mDeviceListLayoutListener = () -> {
         // Set max height for list
@@ -114,12 +110,9 @@
         mHeaderSubtitle = mDialogView.requireViewById(R.id.header_subtitle);
         mHeaderIcon = mDialogView.requireViewById(R.id.header_icon);
         mDevicesRecyclerView = mDialogView.requireViewById(R.id.list_result);
-        mGroupItemController = mDialogView.requireViewById(R.id.group_item_controller);
-        mGroupDivider = mDialogView.requireViewById(R.id.group_item_divider);
         mDeviceListLayout = mDialogView.requireViewById(R.id.device_list);
         mDoneButton = mDialogView.requireViewById(R.id.done);
         mStopButton = mDialogView.requireViewById(R.id.stop);
-        mListBottomPadding = mDialogView.requireViewById(R.id.list_bottom_padding);
 
         mDeviceListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
                 mDeviceListLayoutListener);
@@ -162,7 +155,9 @@
         }
         if (mHeaderIcon.getVisibility() == View.VISIBLE) {
             final int size = getHeaderIconSize();
-            mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size, size));
+            final int padding = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.media_output_dialog_header_icon_padding);
+            mHeaderIcon.setLayoutParams(new LinearLayout.LayoutParams(size + padding, size));
         }
         // Update title and subtitle
         mHeaderTitle.setText(getHeaderText());
@@ -178,12 +173,8 @@
         if (!mAdapter.isDragging()) {
             mAdapter.notifyDataSetChanged();
         }
-        // Add extra padding when device amount is less than 6
-        if (mMediaOutputController.getMediaDevices().size() < 6) {
-            mListBottomPadding.setVisibility(View.VISIBLE);
-        } else {
-            mListBottomPadding.setVisibility(View.GONE);
-        }
+        // Show when remote media session is available
+        mStopButton.setVisibility(getStopButtonVisibility());
     }
 
     abstract int getHeaderIconRes();
@@ -196,6 +187,8 @@
 
     abstract CharSequence getHeaderSubtitle();
 
+    abstract int getStopButtonVisibility();
+
     @Override
     public void onMediaChanged() {
         mMainThreadHandler.post(() -> refresh());
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
index 64d20a27..b1f1bda 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputController.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.media.MediaMetadata;
+import android.media.MediaRoute2Info;
 import android.media.RoutingSessionInfo;
 import android.media.session.MediaController;
 import android.media.session.MediaSessionManager;
@@ -63,7 +64,7 @@
 public class MediaOutputController implements LocalMediaManager.DeviceCallback{
 
     private static final String TAG = "MediaOutputController";
-    private static final boolean DEBUG = false;
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final String mPackageName;
     private final Context mContext;
@@ -406,6 +407,14 @@
         mActivityStarter.dismissKeyguardThenExecute(postKeyguardAction, null, true);
     }
 
+    boolean isActiveRemoteDevice(@NonNull MediaDevice device) {
+        final List<String> features = device.getFeatures();
+        return (features.contains(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK)
+                || features.contains(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK));
+    }
+
     private final MediaController.Callback mCb = new MediaController.Callback() {
         @Override
         public void onMetadataChanged(MediaMetadata metadata) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
index d59971d..c0138f0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputDialog.java
@@ -46,8 +46,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        mGroupItemController.setVisibility(View.GONE);
-        mGroupDivider.setVisibility(View.GONE);
     }
 
     @Override
@@ -75,4 +73,10 @@
     CharSequence getHeaderSubtitle() {
         return mMediaOutputController.getHeaderSubTitle();
     }
+
+    @Override
+    int getStopButtonVisibility() {
+        return mMediaOutputController.isActiveRemoteDevice(
+                mMediaOutputController.getCurrentConnectedMediaDevice()) ? View.VISIBLE : View.GONE;
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
index 42b21c6..27b5b7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputBaseDialogTest.java
@@ -36,7 +36,6 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
-import com.android.settingslib.media.MediaDevice;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ActivityStarter;
@@ -55,7 +54,6 @@
 
     // Mock
     private MediaOutputBaseAdapter mMediaOutputBaseAdapter = mock(MediaOutputBaseAdapter.class);
-
     private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
     private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
     private ShadeController mShadeController = mock(ShadeController.class);
@@ -157,30 +155,6 @@
         verify(mMediaOutputBaseAdapter).notifyDataSetChanged();
     }
 
-    @Test
-    public void refresh_with6Devices_checkBottomPaddingVisibility() {
-        for (int i = 0; i < 6; i++) {
-            mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
-        }
-        mMediaOutputBaseDialogImpl.refresh();
-        final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
-                R.id.list_bottom_padding);
-
-        assertThat(view.getVisibility()).isEqualTo(View.GONE);
-    }
-
-    @Test
-    public void refresh_with5Devices_checkBottomPaddingVisibility() {
-        for (int i = 0; i < 5; i++) {
-            mMediaOutputController.mMediaDevices.add(mock(MediaDevice.class));
-        }
-        mMediaOutputBaseDialogImpl.refresh();
-        final View view = mMediaOutputBaseDialogImpl.mDialogView.requireViewById(
-                R.id.list_bottom_padding);
-
-        assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
-    }
-
     class MediaOutputBaseDialogImpl extends MediaOutputBaseDialog {
 
         MediaOutputBaseDialogImpl(Context context, MediaOutputController mediaOutputController) {
@@ -189,24 +163,34 @@
             mAdapter = mMediaOutputBaseAdapter;
         }
 
+        @Override
         int getHeaderIconRes() {
             return mHeaderIconRes;
         }
 
+        @Override
         IconCompat getHeaderIcon() {
             return mIconCompat;
         }
 
+        @Override
         int getHeaderIconSize() {
             return 10;
         }
 
+        @Override
         CharSequence getHeaderText() {
             return mHeaderTitle;
         }
 
+        @Override
         CharSequence getHeaderSubtitle() {
             return mHeaderSubtitle;
         }
+
+        @Override
+        int getStopButtonVisibility() {
+            return 0;
+        }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
new file mode 100644
index 0000000..ca328fb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaOutputDialogTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.media.dialog;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.media.MediaRoute2Info;
+import android.media.session.MediaSessionManager;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.settingslib.bluetooth.LocalBluetoothManager;
+import com.android.settingslib.media.LocalMediaManager;
+import com.android.settingslib.media.MediaDevice;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.statusbar.phone.ShadeController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@TestableLooper.RunWithLooper
+public class MediaOutputDialogTest extends SysuiTestCase {
+
+    private static final String TEST_PACKAGE = "test_package";
+
+    // Mock
+    private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
+    private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
+    private ShadeController mShadeController = mock(ShadeController.class);
+    private ActivityStarter mStarter = mock(ActivityStarter.class);
+    private LocalMediaManager mLocalMediaManager = mock(LocalMediaManager.class);
+    private MediaDevice mMediaDevice = mock(MediaDevice.class);
+
+    private MediaOutputDialog mMediaOutputDialog;
+    private MediaOutputController mMediaOutputController;
+    private List<String> mFeatures = new ArrayList<>();
+
+    @Before
+    public void setUp() {
+        mMediaOutputController = new MediaOutputController(mContext, TEST_PACKAGE,
+                mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter);
+        mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
+        mMediaOutputDialog = new MediaOutputDialog(mContext, false, mMediaOutputController);
+
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(mMediaDevice);
+        when(mMediaDevice.getFeatures()).thenReturn(mFeatures);
+    }
+
+    @Test
+    public void getStopButtonVisibility_remoteDevice_returnVisible() {
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_AUDIO_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_VIDEO_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+
+        mFeatures.clear();
+        mFeatures.add(MediaRoute2Info.FEATURE_REMOTE_GROUP_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.VISIBLE);
+    }
+
+    @Test
+    public void getStopButtonVisibility_localDevice_returnGone() {
+        mFeatures.add(MediaRoute2Info.FEATURE_LOCAL_PLAYBACK);
+
+        assertThat(mMediaOutputDialog.getStopButtonVisibility()).isEqualTo(View.GONE);
+    }
+
+}