Handle ransferring state in output switcher

-Add subtitle on Slice item for transferring and failed case
-Add test cases

Bug: 150903460
Test: make -j50 RunSettingsRoboTests
Change-Id: I45fee20194dc6c9ec86ca88158393dfda455d0c0
diff --git a/src/com/android/settings/media/MediaDeviceUpdateWorker.java b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
index 7557fd9..281d23e 100644
--- a/src/com/android/settings/media/MediaDeviceUpdateWorker.java
+++ b/src/com/android/settings/media/MediaDeviceUpdateWorker.java
@@ -112,6 +112,11 @@
         notifySliceChange();
     }
 
+    @Override
+    public void onRequestFailed(int reason) {
+        notifySliceChange();
+    }
+
     public Collection<MediaDevice> getMediaDevices() {
         return mMediaDevices;
     }
@@ -119,6 +124,9 @@
     public void connectDevice(MediaDevice device) {
         ThreadUtils.postOnBackgroundThread(() -> {
             mLocalMediaManager.connectDevice(device);
+            ThreadUtils.postOnMainThread(() -> {
+                notifySliceChange();
+            });
         });
     }
 
diff --git a/src/com/android/settings/media/MediaOutputSlice.java b/src/com/android/settings/media/MediaOutputSlice.java
index 318a50d..785d1df 100644
--- a/src/com/android/settings/media/MediaOutputSlice.java
+++ b/src/com/android/settings/media/MediaOutputSlice.java
@@ -42,6 +42,7 @@
 import com.android.settings.slices.CustomSliceable;
 import com.android.settings.slices.SliceBackgroundWorker;
 import com.android.settings.slices.SliceBroadcastReceiver;
+import com.android.settingslib.media.LocalMediaManager;
 import com.android.settingslib.media.MediaDevice;
 import com.android.settingslib.media.MediaOutputSliceConstants;
 
@@ -246,6 +247,15 @@
             rowBuilder.setTitle(deviceName);
             rowBuilder.setPrimaryAction(SliceAction.create(broadcastAction, deviceIcon,
                     ListBuilder.ICON_IMAGE, deviceName));
+            switch (device.getState()) {
+                case LocalMediaManager.MediaDeviceState.STATE_CONNECTING:
+                    rowBuilder.setSubtitle(mContext.getText(R.string.media_output_switching));
+                    break;
+                case LocalMediaManager.MediaDeviceState.STATE_CONNECTING_FAILED:
+                    rowBuilder.setSubtitle(mContext.getText(
+                            R.string.media_output_switch_error_text));
+                    break;
+            }
         }
 
         return rowBuilder;
diff --git a/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java b/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java
index f92b012..8014e56 100644
--- a/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaDeviceUpdateWorkerTest.java
@@ -30,6 +30,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.media.AudioManager;
+import android.media.MediaRoute2ProviderService;
 import android.net.Uri;
 
 import com.android.settings.testutils.shadow.ShadowAudioManager;
@@ -95,7 +96,8 @@
 
     @Test
     public void onSelectedDeviceStateChanged_shouldNotifyChange() {
-        mMediaDeviceUpdateWorker.onSelectedDeviceStateChanged(null, 0);
+        mMediaDeviceUpdateWorker.onSelectedDeviceStateChanged(mMediaDevice1,
+                LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
 
         verify(mResolver).notifyChange(URI, null);
     }
@@ -156,6 +158,13 @@
     }
 
     @Test
+    public void onRequestFailed_shouldNotifyChange() {
+        mMediaDeviceUpdateWorker.onRequestFailed(MediaRoute2ProviderService.REASON_UNKNOWN_ERROR);
+
+        verify(mResolver).notifyChange(URI, null /* observer */);
+    }
+
+    @Test
     public void onReceive_inCallState_shouldNotifyChange() {
         mMediaDeviceUpdateWorker.mLocalMediaManager = mock(LocalMediaManager.class);
         mAudioManager.setMode(AudioManager.MODE_IN_CALL);
diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
index 03d85b2..426eacc 100644
--- a/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
+++ b/tests/robotests/src/com/android/settings/media/MediaOutputSliceTest.java
@@ -336,6 +336,81 @@
     }
 
     @Test
+    public void getSlice_onTransferring_containTransferringSubtitle() {
+        final List<MediaDevice> mSelectedDevices = new ArrayList<>();
+        final List<MediaDevice> mSelectableDevices = new ArrayList<>();
+        mDevices.clear();
+        final MediaDevice device = mock(MediaDevice.class);
+        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
+        when(device.getIcon()).thenReturn(mTestDrawable);
+        when(device.getMaxVolume()).thenReturn(100);
+        when(device.isConnected()).thenReturn(true);
+        when(device.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
+        when(device.getId()).thenReturn(TEST_DEVICE_1_ID);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        when(device2.getName()).thenReturn(TEST_DEVICE_2_NAME);
+        when(device2.getIcon()).thenReturn(mTestDrawable);
+        when(device2.getMaxVolume()).thenReturn(100);
+        when(device2.isConnected()).thenReturn(false);
+        when(device2.getState()).thenReturn(LocalMediaManager.MediaDeviceState.STATE_CONNECTING);
+        when(device2.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
+        when(device2.getId()).thenReturn(TEST_DEVICE_2_ID);
+        mSelectedDevices.add(device);
+        mSelectableDevices.add(device2);
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);
+        mDevices.add(device);
+        mDevices.add(device2);
+        when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mSelectedDevices);
+        when(mLocalMediaManager.getSelectableMediaDevice()).thenReturn(mSelectableDevices);
+        mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
+
+        final Slice mediaSlice = mMediaOutputSlice.getSlice();
+        final String sliceInfo = SliceQuery.findAll(mediaSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+                null).toString();
+
+        assertThat(TextUtils.indexOf(sliceInfo, mContext.getText(R.string.media_output_switching)))
+                .isNotEqualTo(-1);
+    }
+
+    @Test
+    public void getSlice_onTransferringFailed_containFailedSubtitle() {
+        final List<MediaDevice> mSelectedDevices = new ArrayList<>();
+        final List<MediaDevice> mSelectableDevices = new ArrayList<>();
+        mDevices.clear();
+        final MediaDevice device = mock(MediaDevice.class);
+        when(device.getName()).thenReturn(TEST_DEVICE_1_NAME);
+        when(device.getIcon()).thenReturn(mTestDrawable);
+        when(device.getMaxVolume()).thenReturn(100);
+        when(device.isConnected()).thenReturn(true);
+        when(device.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
+        when(device.getId()).thenReturn(TEST_DEVICE_1_ID);
+        final MediaDevice device2 = mock(MediaDevice.class);
+        when(device2.getName()).thenReturn(TEST_DEVICE_2_NAME);
+        when(device2.getIcon()).thenReturn(mTestDrawable);
+        when(device2.getMaxVolume()).thenReturn(100);
+        when(device2.isConnected()).thenReturn(false);
+        when(device2.getState()).thenReturn(LocalMediaManager.MediaDeviceState
+                .STATE_CONNECTING_FAILED);
+        when(device2.getDeviceType()).thenReturn(MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
+        when(device2.getId()).thenReturn(TEST_DEVICE_2_ID);
+        mSelectedDevices.add(device);
+        mSelectableDevices.add(device2);
+        when(mLocalMediaManager.getCurrentConnectedDevice()).thenReturn(device);
+        mDevices.add(device);
+        mDevices.add(device2);
+        when(mLocalMediaManager.getSelectedMediaDevice()).thenReturn(mSelectedDevices);
+        when(mLocalMediaManager.getSelectableMediaDevice()).thenReturn(mSelectableDevices);
+        mMediaDeviceUpdateWorker.onDeviceListUpdate(mDevices);
+
+        final Slice mediaSlice = mMediaOutputSlice.getSlice();
+        final String sliceInfo = SliceQuery.findAll(mediaSlice, FORMAT_SLICE, HINT_LIST_ITEM,
+                null).toString();
+
+        assertThat(TextUtils.indexOf(sliceInfo, mContext.getText(
+                R.string.media_output_switch_error_text))).isNotEqualTo(-1);
+    }
+
+    @Test
     public void onNotifyChange_foundMediaDevice_connect() {
         mDevices.clear();
         final MediaDevice device = mock(MediaDevice.class);