OSDN Git Service

Sound + Output Switcher on Sound Setting
authortimhypeng <timhypeng@google.com>
Mon, 4 Mar 2019 08:32:47 +0000 (16:32 +0800)
committertim peng <timhypeng@google.com>
Tue, 12 Mar 2019 03:07:36 +0000 (03:07 +0000)
1. Show "play media to" item when Previously Connected device is available
2. Click "Play media to" to launch output slice
3. Update test case

Bug: 126475101
Test: make -j50 RunSettingsRoboTests
Change-Id: Id8afd1a2407acb78c11e81d2420ae8c16130a321

res/xml/sound_settings.xml
src/com/android/settings/notification/SoundSettings.java
src/com/android/settings/sound/AudioSwitchPreferenceController.java
src/com/android/settings/sound/HandsFreeProfileOutputPreferenceController.java
src/com/android/settings/sound/MediaOutputPreferenceController.java
tests/robotests/src/com/android/settings/sound/AudioOutputSwitchPreferenceControllerTest.java
tests/robotests/src/com/android/settings/sound/HandsFreeProfileOutputPreferenceControllerTest.java
tests/robotests/src/com/android/settings/sound/MediaOutputPreferenceControllerTest.java

index 81a0453..57bee1f 100644 (file)
@@ -41,7 +41,7 @@
         settings:controller="com.android.settings.notification.MediaVolumePreferenceController"/>
 
     <!-- Media output switcher -->
-    <ListPreference
+    <Preference
         android:key="media_output"
         android:title="@string/media_output_title"
         android:dialogTitle="@string/media_output_title"
index b26b921..eec0fb8 100644 (file)
@@ -38,7 +38,6 @@ import com.android.settings.core.OnActivityResultListener;
 import com.android.settings.dashboard.DashboardFragment;
 import com.android.settings.search.BaseSearchIndexProvider;
 import com.android.settings.sound.HandsFreeProfileOutputPreferenceController;
-import com.android.settings.sound.MediaOutputPreferenceController;
 import com.android.settings.widget.PreferenceCategoryController;
 import com.android.settings.widget.UpdatableListPreferenceDialogFragment;
 import com.android.settingslib.core.AbstractPreferenceController;
@@ -77,7 +76,6 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
 
     private RingtonePreference mRequestPreference;
     private UpdatableListPreferenceDialogFragment mDialogFragment;
-    private String mMediaOutputControllerKey;
     private String mHfpOutputControllerKey;
 
     @Override
@@ -132,8 +130,6 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
         final int metricsCategory;
         if (mHfpOutputControllerKey.equals(preference.getKey())) {
             metricsCategory = SettingsEnums.DIALOG_SWITCH_HFP_DEVICES;
-        } else if (mMediaOutputControllerKey.equals(preference.getKey())) {
-            metricsCategory = SettingsEnums.DIALOG_SWITCH_A2DP_DEVICES;
         } else {
             metricsCategory = Instrumentable.METRICS_CATEGORY_UNKNOWN;
         }
@@ -186,9 +182,6 @@ public class SoundSettings extends DashboardFragment implements OnActivityResult
         volumeControllers.add(use(CallVolumePreferenceController.class));
         volumeControllers.add(use(RemoteVolumePreferenceController.class));
 
-        use(MediaOutputPreferenceController.class).setCallback(listPreference ->
-                onPreferenceDataChanged(listPreference));
-        mMediaOutputControllerKey = use(MediaOutputPreferenceController.class).getPreferenceKey();
         use(HandsFreeProfileOutputPreferenceController.class).setCallback(listPreference ->
                 onPreferenceDataChanged(listPreference));
         mHfpOutputControllerKey =
index f77dfca..0da0f21 100644 (file)
@@ -32,7 +32,6 @@ import android.media.MediaRouter;
 import android.media.MediaRouter.Callback;
 import android.os.Handler;
 import android.os.Looper;
-import android.text.TextUtils;
 import android.util.FeatureFlagUtils;
 import android.util.Log;
 
@@ -40,7 +39,6 @@ import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 import androidx.preference.PreferenceScreen;
 
-import com.android.settings.R;
 import com.android.settings.bluetooth.Utils;
 import com.android.settings.core.BasePreferenceController;
 import com.android.settings.core.FeatureFlags;
@@ -63,15 +61,11 @@ import java.util.concurrent.FutureTask;
 /**
  * Abstract class for audio switcher controller to notify subclass
  * updating the current status of switcher entry. Subclasses must overwrite
- * {@link #setActiveBluetoothDevice(BluetoothDevice)} to set the
- * active device for corresponding profile.
  */
 public abstract class AudioSwitchPreferenceController extends BasePreferenceController
-        implements Preference.OnPreferenceChangeListener, BluetoothCallback,
-        LifecycleObserver, OnStart, OnStop {
+        implements BluetoothCallback, LifecycleObserver, OnStart, OnStop {
 
     private static final String TAG = "AudioSwitchPrefCtrl";
-    private static final int INVALID_INDEX = -1;
 
     protected final List<BluetoothDevice> mConnectedDevices;
     protected final AudioManager mAudioManager;
@@ -129,35 +123,6 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
     }
 
     @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final String address = (String) newValue;
-        if (!(preference instanceof ListPreference)) {
-            return false;
-        }
-
-        final ListPreference listPreference = (ListPreference) preference;
-        if (TextUtils.equals(address, mContext.getText(R.string.media_output_default_summary))) {
-            // Switch to default device which address is device name
-            mSelectedIndex = getDefaultDeviceIndex();
-            setActiveBluetoothDevice(null);
-            listPreference.setSummary(mContext.getText(R.string.media_output_default_summary));
-        } else {
-            // Switch to BT device which address is hardware address
-            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
-            if (connectedDeviceIndex == INVALID_INDEX) {
-                return false;
-            }
-            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
-            mSelectedIndex = connectedDeviceIndex;
-            setActiveBluetoothDevice(btDevice);
-            listPreference.setSummary(btDevice.getAliasName());
-        }
-        return true;
-    }
-
-    public abstract void setActiveBluetoothDevice(BluetoothDevice device);
-
-    @Override
     public void displayPreference(PreferenceScreen screen) {
         super.displayPreference(screen);
         mPreference = screen.findPreference(mPreferenceKey);
@@ -185,6 +150,12 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
     }
 
     @Override
+    public void onBluetoothStateChanged(int bluetoothState) {
+        // To handle the case that Bluetooth on and no connected devices
+        updateState(mPreference);
+    }
+
+    @Override
     public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) {
         updateState(mPreference);
     }
@@ -236,17 +207,34 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
     }
 
     /**
-     * get A2dp connected device
+     * get A2dp devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
      */
-    protected List<BluetoothDevice> getConnectedA2dpDevices() {
-        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+    protected List<BluetoothDevice> getConnectableA2dpDevices() {
         final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
         if (a2dpProfile == null) {
+            return new ArrayList<>();
+        }
+        return a2dpProfile.getConnectableDevices();
+    }
+
+    /**
+     * get hearing aid profile connected device, exclude other devices with same hiSyncId.
+     */
+    protected List<BluetoothDevice> getConnectedHearingAidDevices() {
+        final List<BluetoothDevice> connectedDevices = new ArrayList<>();
+        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
+        if (hapProfile == null) {
             return connectedDevices;
         }
-        final List<BluetoothDevice> devices = a2dpProfile.getConnectedDevices();
+        final List<Long> devicesHiSyncIds = new ArrayList<>();
+        final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
         for (BluetoothDevice device : devices) {
-            if (device.isConnected()) {
+            final long hiSyncId = hapProfile.getHiSyncId(device);
+            // device with same hiSyncId should not be shown in the UI.
+            // So do not add it into connectedDevices.
+            if (!devicesHiSyncIds.contains(hiSyncId) && device.isConnected()) {
+                devicesHiSyncIds.add(hiSyncId);
                 connectedDevices.add(device);
             }
         }
@@ -254,21 +242,23 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
     }
 
     /**
-     * get hearing aid profile connected device, exclude other devices with same hiSyncId.
+     * get hearing aid profile devices on all states
+     * (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED,  STATE_DISCONNECTING)
+     * exclude other devices with same hiSyncId.
      */
-    protected List<BluetoothDevice> getConnectedHearingAidDevices() {
+    protected List<BluetoothDevice> getConnectableHearingAidDevices() {
         final List<BluetoothDevice> connectedDevices = new ArrayList<>();
         final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
         if (hapProfile == null) {
             return connectedDevices;
         }
         final List<Long> devicesHiSyncIds = new ArrayList<>();
-        final List<BluetoothDevice> devices = hapProfile.getConnectedDevices();
+        final List<BluetoothDevice> devices = hapProfile.getConnectableDevices();
         for (BluetoothDevice device : devices) {
             final long hiSyncId = hapProfile.getHiSyncId(device);
             // device with same hiSyncId should not be shown in the UI.
             // So do not add it into connectedDevices.
-            if (!devicesHiSyncIds.contains(hiSyncId) && device.isConnected()) {
+            if (!devicesHiSyncIds.contains(hiSyncId)) {
                 devicesHiSyncIds.add(hiSyncId);
                 connectedDevices.add(device);
             }
@@ -306,52 +296,6 @@ public abstract class AudioSwitchPreferenceController extends BasePreferenceCont
      */
     public abstract BluetoothDevice findActiveDevice();
 
-    int getDefaultDeviceIndex() {
-        // Default device is after all connected devices.
-        return mConnectedDevices.size();
-    }
-
-    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            BluetoothDevice activeDevice) {
-        // default to current device
-        mSelectedIndex = getDefaultDeviceIndex();
-        // default device is after all connected devices.
-        mediaOutputs[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        // use default device name as address
-        mediaValues[mSelectedIndex] = mContext.getText(R.string.media_output_default_summary);
-        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-            final BluetoothDevice btDevice = mConnectedDevices.get(i);
-            mediaOutputs[i] = btDevice.getAliasName();
-            mediaValues[i] = btDevice.getAddress();
-            if (btDevice.equals(activeDevice)) {
-                // select the active connected device.
-                mSelectedIndex = i;
-            }
-        }
-    }
-
-    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
-            Preference preference) {
-        final ListPreference listPreference = (ListPreference) preference;
-        listPreference.setEntries(mediaOutputs);
-        listPreference.setEntryValues(mediaValues);
-        listPreference.setValueIndex(mSelectedIndex);
-        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
-        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
-    }
-
-    private int getConnectedDeviceIndex(String hardwareAddress) {
-        if (mConnectedDevices != null) {
-            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
-                final BluetoothDevice btDevice = mConnectedDevices.get(i);
-                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
-                    return i;
-                }
-            }
-        }
-        return INVALID_INDEX;
-    }
-
     private void register() {
         mLocalBluetoothManager.getEventManager().registerCallback(this);
         mAudioManager.registerAudioDeviceCallback(mAudioManagerAudioDeviceCallback, mHandler);
index a02c0b2..9157477 100644 (file)
@@ -20,7 +20,9 @@ import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.text.TextUtils;
 
+import androidx.preference.ListPreference;
 import androidx.preference.Preference;
 
 import com.android.settings.R;
@@ -32,14 +34,56 @@ import com.android.settingslib.bluetooth.HearingAidProfile;
  * This class allows switching between HFP-connected & HAP-connected BT devices
  * while in on-call state.
  */
-public class HandsFreeProfileOutputPreferenceController extends
-        AudioSwitchPreferenceController {
+public class HandsFreeProfileOutputPreferenceController extends AudioSwitchPreferenceController
+        implements Preference.OnPreferenceChangeListener {
+
+    private static final int INVALID_INDEX = -1;
 
     public HandsFreeProfileOutputPreferenceController(Context context, String key) {
         super(context, key);
     }
 
     @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        final String address = (String) newValue;
+        if (!(preference instanceof ListPreference)) {
+            return false;
+        }
+
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        final ListPreference listPreference = (ListPreference) preference;
+        if (TextUtils.equals(address, defaultSummary)) {
+            // Switch to default device which address is device name
+            mSelectedIndex = getDefaultDeviceIndex();
+            setActiveBluetoothDevice(null);
+            listPreference.setSummary(defaultSummary);
+        } else {
+            // Switch to BT device which address is hardware address
+            final int connectedDeviceIndex = getConnectedDeviceIndex(address);
+            if (connectedDeviceIndex == INVALID_INDEX) {
+                return false;
+            }
+            final BluetoothDevice btDevice = mConnectedDevices.get(connectedDeviceIndex);
+            mSelectedIndex = connectedDeviceIndex;
+            setActiveBluetoothDevice(btDevice);
+            listPreference.setSummary(btDevice.getAliasName());
+        }
+        return true;
+    }
+
+    private int getConnectedDeviceIndex(String hardwareAddress) {
+        if (mConnectedDevices != null) {
+            for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+                final BluetoothDevice btDevice = mConnectedDevices.get(i);
+                if (TextUtils.equals(btDevice.getAddress(), hardwareAddress)) {
+                    return i;
+                }
+            }
+        }
+        return INVALID_INDEX;
+    }
+
+    @Override
     public void updateState(Preference preference) {
         if (preference == null) {
             // In case UI is not ready.
@@ -83,7 +127,41 @@ public class HandsFreeProfileOutputPreferenceController extends
         setPreference(mediaOutputs, mediaValues, preference);
     }
 
-    @Override
+    int getDefaultDeviceIndex() {
+        // Default device is after all connected devices.
+        return mConnectedDevices.size();
+    }
+
+    void setupPreferenceEntries(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            BluetoothDevice activeDevice) {
+        // default to current device
+        mSelectedIndex = getDefaultDeviceIndex();
+        // default device is after all connected devices.
+        final CharSequence defaultSummary = mContext.getText(R.string.media_output_default_summary);
+        mediaOutputs[mSelectedIndex] = defaultSummary;
+        // use default device name as address
+        mediaValues[mSelectedIndex] = defaultSummary;
+        for (int i = 0, size = mConnectedDevices.size(); i < size; i++) {
+            final BluetoothDevice btDevice = mConnectedDevices.get(i);
+            mediaOutputs[i] = btDevice.getAliasName();
+            mediaValues[i] = btDevice.getAddress();
+            if (btDevice.equals(activeDevice)) {
+                // select the active connected device.
+                mSelectedIndex = i;
+            }
+        }
+    }
+
+    void setPreference(CharSequence[] mediaOutputs, CharSequence[] mediaValues,
+            Preference preference) {
+        final ListPreference listPreference = (ListPreference) preference;
+        listPreference.setEntries(mediaOutputs);
+        listPreference.setEntryValues(mediaValues);
+        listPreference.setValueIndex(mSelectedIndex);
+        listPreference.setSummary(mediaOutputs[mSelectedIndex]);
+        mAudioSwitchPreferenceCallback.onPreferenceDataChanged(listPreference);
+    }
+
     public void setActiveBluetoothDevice(BluetoothDevice device) {
         if (!Utils.isAudioModeOngoingCall(mContext)) {
             return;
index ce476ad..47810f7 100644 (file)
 
 package com.android.settings.sound;
 
-import static android.bluetooth.IBluetoothHearingAid.HI_SYNC_ID_INVALID;
 import static android.media.AudioManager.STREAM_MUSIC;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
+import android.text.TextUtils;
 
 import androidx.preference.Preference;
 
@@ -30,12 +31,16 @@ import com.android.settings.R;
 import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.HearingAidProfile;
+import com.android.settingslib.media.MediaOutputSliceConstants;
+
+import java.util.List;
 
 /**
- * This class which allows switching between A2dp-connected & HAP-connected BT devices.
- * A few conditions will disable this switcher:
- * - No available BT device(s)
- * - Media stream captured by cast device
+ * This class allows launching MediaOutputSlice to switch output device.
+ * Preference would hide only when
+ * - Bluetooth = OFF
+ * - Bluetooth = ON and Connected Devices = 0 and Previously Connected = 0
+ * - Media stream captured by remote device
  * - During a call.
  */
 public class MediaOutputPreferenceController extends AudioSwitchPreferenceController {
@@ -66,40 +71,22 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
             return;
         }
 
-        mConnectedDevices.clear();
-        // Otherwise, list all of the A2DP connected device and display the active device.
-        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL) {
-            mConnectedDevices.addAll(getConnectedA2dpDevices());
-            mConnectedDevices.addAll(getConnectedHearingAidDevices());
-        }
-
-        final int numDevices = mConnectedDevices.size();
-        mPreference.setVisible((numDevices == 0) ? false : true);
-        CharSequence[] mediaOutputs = new CharSequence[numDevices + 1];
-        CharSequence[] mediaValues = new CharSequence[numDevices + 1];
-
-        // Setup devices entries, select active connected device
-        setupPreferenceEntries(mediaOutputs, mediaValues, findActiveDevice());
-
-        // Display connected devices, default device and show the active device
-        setPreference(mediaOutputs, mediaValues, preference);
-    }
-
-    @Override
-    public void setActiveBluetoothDevice(BluetoothDevice device) {
-        if (mAudioManager.getMode() != AudioManager.MODE_NORMAL) {
-            return;
-        }
-        final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile();
-        final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile();
-        if (hapProfile != null && a2dpProfile != null && device == null) {
-            hapProfile.setActiveDevice(null);
-            a2dpProfile.setActiveDevice(null);
-        } else if (hapProfile != null && hapProfile.getHiSyncId(device) != HI_SYNC_ID_INVALID) {
-            hapProfile.setActiveDevice(device);
-        } else if (a2dpProfile != null) {
-            a2dpProfile.setActiveDevice(device);
+        boolean deviceConnectable = false;
+        BluetoothDevice activeDevice = null;
+        // Show preference if there is connected or previously connected device
+        // Find active device and set its name as the preference's summary
+        List<BluetoothDevice> connectableA2dpDevices = getConnectableA2dpDevices();
+        List<BluetoothDevice> connectableHADevices = getConnectableHearingAidDevices();
+        if (mAudioManager.getMode() == AudioManager.MODE_NORMAL
+                && ((connectableA2dpDevices != null && !connectableA2dpDevices.isEmpty())
+                || (connectableHADevices != null && !connectableHADevices.isEmpty()))) {
+            deviceConnectable = true;
+            activeDevice = findActiveDevice();
         }
+        mPreference.setVisible(deviceConnectable);
+        mPreference.setSummary((activeDevice == null) ?
+                mContext.getText(R.string.media_output_default_summary) :
+                activeDevice.getAliasName());
     }
 
     @Override
@@ -112,4 +99,34 @@ public class MediaOutputPreferenceController extends AudioSwitchPreferenceContro
         }
         return activeDevice;
     }
+
+    /**
+     * Find active hearing aid device
+     */
+    @Override
+    protected BluetoothDevice findActiveHearingAidDevice() {
+        final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
+
+        if (hearingAidProfile != null) {
+            List<BluetoothDevice> activeDevices = hearingAidProfile.getActiveDevices();
+            for (BluetoothDevice btDevice : activeDevices) {
+                if (btDevice != null) {
+                    return btDevice;
+                }
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (TextUtils.equals(preference.getKey(), getPreferenceKey())) {
+            final Intent intent = new Intent()
+                    .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT)
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            mContext.startActivity(intent);
+            return true;
+        }
+        return false;
+    }
 }
index 54a79f4..5b7c863 100644 (file)
@@ -238,63 +238,6 @@ public class AudioOutputSwitchPreferenceControllerTest {
         verify(mLocalBluetoothManager).setForegroundActivity(null);
     }
 
-    @Test
-    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference,
-                mContext.getText(R.string.media_output_default_summary));
-
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.media_output_default_summary));
-    }
-
-    /**
-     * One Bluetooth devices are available, and select the device.
-     * Preference summary should be device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one Bluetooth devices are available, and select second device.
-     * Preference summary should be second device name.
-     */
-    @Test
-    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
-        ShadowBluetoothDevice shadowBluetoothDevice;
-        BluetoothDevice secondBluetoothDevice;
-        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
-        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
-        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
-        mController.mConnectedDevices.clear();
-        mController.mConnectedDevices.add(mBluetoothDevice);
-        mController.mConnectedDevices.add(secondBluetoothDevice);
-
-        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
-
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
-    }
-
-    /**
-     * mConnectedDevices is empty.
-     * onPreferenceChange should return false.
-     */
-    @Test
-    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
-        mController.mConnectedDevices.clear();
-
-        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
-    }
-
     /**
      * Audio stream output to bluetooth sco headset which is the subset of all sco device.
      * isStreamFromOutputDevice should return true.
@@ -416,39 +359,6 @@ public class AudioOutputSwitchPreferenceControllerTest {
     }
 
     /**
-     * One A2dp device is connected.
-     * getConnectedA2dpDevices should add this device to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_oneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice);
-    }
-
-    /**
-     * More than one A2dp devices are connected.
-     * getConnectedA2dpDevices should add all devices to list.
-     */
-    @Test
-    public void getConnectedA2dpDevices_moreThanOneConnectedA2dpDevice_shouldAddDeviceToList() {
-        mEmptyDevices.clear();
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-
-        mEmptyDevices.addAll(mController.getConnectedA2dpDevices());
-
-        assertThat(mEmptyDevices).containsExactly(mBluetoothDevice, mLeftBluetoothHapDevice);
-    }
-
-    /**
      * One hands free profile device is connected.
      * getConnectedA2dpDevices should add this device to list.
      */
@@ -488,10 +398,6 @@ public class AudioOutputSwitchPreferenceControllerTest {
         }
 
         @Override
-        public void setActiveBluetoothDevice(BluetoothDevice device) {
-        }
-
-        @Override
         public BluetoothDevice findActiveDevice() {
             return null;
         }
index 4010145..0eada60 100644 (file)
@@ -57,6 +57,7 @@ import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
+import org.robolectric.Shadows;
 import org.robolectric.annotation.Config;
 import org.robolectric.shadows.ShadowBluetoothDevice;
 
@@ -107,7 +108,7 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
+    private HandsFreeProfileOutputPreferenceController mController;
     private List<BluetoothDevice> mProfileConnectedDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
@@ -478,4 +479,61 @@ public class HandsFreeProfileOutputPreferenceControllerTest {
 
         assertThat(mController.findActiveDevice()).isNull();
     }
+
+    /**
+     * One Bluetooth devices are available, and select the device.
+     * Preference summary should be device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevice_shouldSetBtDeviceName() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
+    }
+
+    /**
+     * More than one Bluetooth devices are available, and select second device.
+     * Preference summary should be second device name.
+     */
+    @Test
+    public void onPreferenceChange_toBtDevices_shouldSetSecondBtDeviceName() {
+        ShadowBluetoothDevice shadowBluetoothDevice;
+        BluetoothDevice secondBluetoothDevice;
+        secondBluetoothDevice = mBluetoothAdapter.getRemoteDevice(TEST_DEVICE_ADDRESS_2);
+        shadowBluetoothDevice = Shadows.shadowOf(secondBluetoothDevice);
+        shadowBluetoothDevice.setName(TEST_DEVICE_NAME_2);
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+        mController.mConnectedDevices.add(secondBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_2);
+
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
+    }
+
+    /**
+     * mConnectedDevices is empty.
+     * onPreferenceChange should return false.
+     */
+    @Test
+    public void onPreferenceChange_connectedDeviceIsNull_shouldReturnFalse() {
+        mController.mConnectedDevices.clear();
+
+        assertThat(mController.onPreferenceChange(mPreference, TEST_DEVICE_ADDRESS_1)).isFalse();
+    }
+
+    @Test
+    public void onPreferenceChange_toThisDevice_shouldSetDefaultSummary() {
+        mController.mConnectedDevices.clear();
+        mController.mConnectedDevices.add(mBluetoothDevice);
+
+        mController.onPreferenceChange(mPreference,
+                mContext.getText(R.string.media_output_default_summary));
+
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
+    }
 }
index 8c7faef..7fcd3d2 100644 (file)
 package com.android.settings.sound;
 
 import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP;
+import static android.media.AudioSystem.DEVICE_OUT_EARPIECE;
 import static android.media.AudioSystem.DEVICE_OUT_HEARING_AID;
 import static android.media.AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -34,9 +33,10 @@ import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
 import android.content.Context;
+import android.content.Intent;
 import android.media.AudioManager;
 
-import androidx.preference.ListPreference;
+import androidx.preference.Preference;
 import androidx.preference.PreferenceManager;
 import androidx.preference.PreferenceScreen;
 
@@ -49,11 +49,13 @@ import com.android.settingslib.bluetooth.BluetoothEventManager;
 import com.android.settingslib.bluetooth.HearingAidProfile;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.media.MediaOutputSliceConstants;
 
 import org.junit.After;
 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;
@@ -80,8 +82,6 @@ public class MediaOutputPreferenceControllerTest {
     private static final String TEST_DEVICE_ADDRESS_2 = "00:B2:B2:B2:B2:B2";
     private static final String TEST_DEVICE_ADDRESS_3 = "00:C3:C3:C3:C3:C3";
     private static final String TEST_DEVICE_ADDRESS_4 = "00:D4:D4:D4:D4:D4";
-    private final static long HISYNCID1 = 10;
-    private final static long HISYNCID2 = 11;
 
     @Mock
     private LocalBluetoothManager mLocalManager;
@@ -98,7 +98,7 @@ public class MediaOutputPreferenceControllerTest {
 
     private Context mContext;
     private PreferenceScreen mScreen;
-    private ListPreference mPreference;
+    private Preference mPreference;
     private AudioManager mAudioManager;
     private ShadowAudioManager mShadowAudioManager;
     private BluetoothManager mBluetoothManager;
@@ -108,8 +108,8 @@ public class MediaOutputPreferenceControllerTest {
     private BluetoothDevice mLeftBluetoothHapDevice;
     private BluetoothDevice mRightBluetoothHapDevice;
     private LocalBluetoothManager mLocalBluetoothManager;
-    private AudioSwitchPreferenceController mController;
-    private List<BluetoothDevice> mProfileConnectedDevices;
+    private MediaOutputPreferenceController mController;
+    private List<BluetoothDevice> mProfileConnectableDevices;
     private List<BluetoothDevice> mHearingAidActiveDevices;
 
     @Before
@@ -149,8 +149,8 @@ public class MediaOutputPreferenceControllerTest {
 
         mController = new MediaOutputPreferenceController(mContext, TEST_KEY);
         mScreen = spy(new PreferenceScreen(mContext, null));
-        mPreference = new ListPreference(mContext);
-        mProfileConnectedDevices = new ArrayList<>();
+        mPreference = new Preference(mContext);
+        mProfileConnectableDevices = new ArrayList<>();
         mHearingAidActiveDevices = new ArrayList<>(2);
 
         when(mScreen.getPreferenceManager()).thenReturn(mock(PreferenceManager.class));
@@ -166,354 +166,186 @@ public class MediaOutputPreferenceControllerTest {
         ShadowBluetoothUtils.reset();
     }
 
-    /**
-     * In normal mode, bluetooth device with HisyncId.
-     * HearingAidProfile should set active device to this device.
-     */
-    @Test
-    public void setActiveBluetoothDevice_btDeviceWithHisyncId_shouldSetBtDeviceActive() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-
-        mController.setActiveBluetoothDevice(mLeftBluetoothHapDevice);
-
-        verify(mHearingAidProfile).setActiveDevice(mLeftBluetoothHapDevice);
-        verify(mA2dpProfile, never()).setActiveDevice(mLeftBluetoothHapDevice);
-    }
-
-    /**
-     * In normal mode, bluetooth device without HisyncId.
-     * A2dpProfile should set active device to this device.
-     */
-    @Test
-    public void setActiveBluetoothDevice_btDeviceWithoutHisyncId_shouldSetBtDeviceActive() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
-
-        verify(mA2dpProfile).setActiveDevice(mBluetoothDevice);
-        verify(mHearingAidProfile, never()).setActiveDevice(mBluetoothDevice);
-    }
-
-    /**
-     * In normal mode, set active device to "this device".
-     * A2dpProfile should set to null.
-     * HearingAidProfile should set to null.
-     */
-    @Test
-    public void setActiveBluetoothDevice_setNull_shouldSetNullToBothProfiles() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-
-        mController.setActiveBluetoothDevice(null);
-
-        verify(mA2dpProfile).setActiveDevice(null);
-        verify(mHearingAidProfile).setActiveDevice(null);
-    }
 
     /**
-     * During a call
-     * A2dpProfile should not set active device.
-     */
-    @Test
-    public void setActiveBluetoothDevice_duringACall_shouldNotSetActiveDeviceToA2dpProfile() {
-        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
-
-        mController.setActiveBluetoothDevice(mBluetoothDevice);
-
-        verify(mA2dpProfile, times(0)).setActiveDevice(any(BluetoothDevice.class));
-    }
-
-    /**
-     * Default status
+     * A2DP Bluetooth device(s) are not connected nor previously connected
      * Preference should be invisible
-     * Summary should be default summary
      */
     @Test
-    public void updateState_shouldSetSummary() {
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.media_output_default_summary));
-    }
-
-    /**
-     * During a call
-     * Preference should be invisible
-     * Default string should be "Unavailable during calls"
-     */
-    @Test
-    public void updateState_duringACall_shouldSetDefaultSummary() {
-        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getText(R.string.media_out_summary_ongoing_call_state));
-    }
-
-    /**
-     * No available A2dp BT devices:
-     * Preference should be invisible
-     * Preference summary should be "This device"
-     */
-    @Test
-    public void updateState_noAvailableA2dpBtDevices_shouldDisableAndSetDefaultSummary() {
+    public void updateState_withoutConnectableBtDevice_preferenceInvisible() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        List<BluetoothDevice> emptyDeviceList = new ArrayList<>();
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(emptyDeviceList);
-
-        mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isFalse();
-        String defaultString = mContext.getString(R.string.media_output_default_summary);
-        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
-    }
-
-    /**
-     * Media stream is captured by something else (cast device):
-     * Preference should be invisible
-     * Preference summary should be "unavailable"
-     */
-    @Test
-    public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_REMOTE_SUBMIX);
+        mProfileConnectableDevices.clear();
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        mPreference.setVisible(true);
 
+        assertThat(mPreference.isVisible()).isTrue();
         mController.updateState(mPreference);
-
         assertThat(mPreference.isVisible()).isFalse();
-        String defaultString = mContext.getString(R.string.media_output_summary_unavailable);
-        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
     }
 
     /**
-     * One A2DP Bluetooth device is available and active.
+     * A2DP Bluetooth device(s) are connectable, no matter active or inactive
      * Preference should be visible
-     * Preference summary should be the activated device name
      */
     @Test
-    public void updateState_oneA2dpBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+    public void updateState_withConnectableBtDevice_preferenceVisible() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        assertThat(mPreference.isVisible()).isFalse();
 
+        // Without Active Bluetooth Device
         mController.updateState(mPreference);
-
         assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
-    }
-
-    /**
-     * More than one A2DP Bluetooth devices are available, and second device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     */
-    @Test
-    public void updateState_moreThanOneA2DpBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mSecondBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(mSecondBluetoothDevice);
 
+        // With Active Bluetooth Device
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
         mController.updateState(mPreference);
-
         assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_2);
     }
 
     /**
-     * A2DP Bluetooth device(s) are available, but wired headset is plugged in and activated
-     * Preference should be visible
+     * A2DP Bluetooth device(s) are connectable, but no device is set as activated
      * Preference summary should be "This device"
      */
     @Test
-    public void updateState_a2dpDevicesAvailableWiredHeadsetIsActivated_shouldSetDefaultSummary() {
+    public void updateState_withConnectableBtDevice_withoutActiveBtDevice_setDefaultSummary() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_EARPIECE);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(null);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
         when(mA2dpProfile.getActiveDevice()).thenReturn(null);
 
+        assertThat(mPreference.getSummary()).isNull();
         mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
         assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
+                mContext.getText(R.string.media_output_default_summary));
     }
 
-
     /**
-     * A2DP Bluetooth device(s) are available, but current device speaker is activated
-     * Preference should be visible
-     * Preference summary should be "This device"
+     * A2DP Bluetooth device(s) are connected and active
+     * Preference summary should be device's name
      */
     @Test
-    public void updateState_a2dpDevicesAvailableCurrentDeviceActivated_shouldSetDefaultSummary() {
+    public void updateState_withActiveBtDevice_setActivatedDeviceName() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_BLUETOOTH_A2DP);
         mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        when(mA2dpProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mA2dpProfile.getActiveDevice()).thenReturn(null);
+        mProfileConnectableDevices.clear();
+        mProfileConnectableDevices.add(mBluetoothDevice);
+        mProfileConnectableDevices.add(mSecondBluetoothDevice);
+        when(mA2dpProfile.getConnectableDevices()).thenReturn(mProfileConnectableDevices);
+        when(mA2dpProfile.getActiveDevice()).thenReturn(mBluetoothDevice);
 
+        assertThat(mPreference.getSummary()).isNull();
         mController.updateState(mPreference);
-
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(
-                mContext.getString(R.string.media_output_default_summary));
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_DEVICE_NAME_1);
     }
 
+
     /**
-     * One hearing aid profile Bluetooth device is available and active.
+     * Hearing Aid device(s) are connectable, no matter active or inactive
      * Preference should be visible
-     * Preference summary should be the activated device name
      */
     @Test
-    public void updateState_oneHapBtDeviceAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+    public void updateState_withConnectableHADevice_preferenceVisible() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
         mHearingAidActiveDevices.clear();
         mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
+        assertThat(mPreference.isVisible()).isFalse();
 
+        // Without Active Hearing Aid Device
         mController.updateState(mPreference);
+        assertThat(mPreference.isVisible()).isTrue();
 
+        // With Active Hearing Aid Device
+        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
+        mController.updateState(mPreference);
         assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
     }
 
     /**
-     * More than one hearing aid profile Bluetooth devices are available, and second
-     * device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
+     * Hearing Aid device(s) are connected and active
+     * Preference summary should be device's name
      */
     @Test
-    public void updateState_moreThanOneHapBtDevicesAreAvailable_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
+    public void updateState_withActiveHADevice_setActivatedDeviceName() {
         mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
+        mAudioManager.setMode(AudioManager.MODE_NORMAL);
         mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
+        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
+        when(mHearingAidProfile.getConnectableDevices()).thenReturn(mHearingAidActiveDevices);
         when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
 
+        assertThat(mPreference.getSummary()).isNull();
         mController.updateState(mPreference);
+        assertThat(mPreference.getSummary()).isEqualTo(TEST_HAP_DEVICE_NAME_1);
 
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
+    }
+
+    @Test
+    public void click_launch_outputSwitcherSlice() {
+        final ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext, never()).startActivity(intentCaptor.capture());
+
+        mPreference.setKey(TEST_KEY);
+        mController.handlePreferenceTreeClick(mPreference);
+        verify(mContext).startActivity(intentCaptor.capture());
+        assertThat(intentCaptor.getValue().getAction())
+                .isEqualTo(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT);
     }
 
     /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId are active. Both of HAP device are active,
-     * "left" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
+     * Default status
+     * Preference should be invisible
+     * Summary should be default summary
      */
     @Test
-    public void updateState_hapBtDeviceWithSameId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
-
+    public void updateState_shouldSetSummary() {
         mController.updateState(mPreference);
 
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mLeftBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isFalse();
+        assertThat(mPreference.isVisible()).isFalse();
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_output_default_summary));
     }
 
     /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with same HisyncId. Both of HAP device are active,
-     * "right" side HAP device is added first.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should not contain second HAP device with same HisyncId
+     * During a call
+     * Preference should be invisible
+     * Default string should be "Unavailable during calls"
      */
     @Test
-    public void updateState_hapBtDeviceWithSameIdButDifferentOrder_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        //with same HisyncId, first one will remain in UI.
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(mLeftBluetoothHapDevice);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID1);
+    public void updateState_duringACall_shouldSetDefaultSummary() {
+        mAudioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
 
         mController.updateState(mPreference);
 
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices.contains(mRightBluetoothHapDevice)).isTrue();
-        assertThat(mController.mConnectedDevices.contains(mLeftBluetoothHapDevice)).isFalse();
+        assertThat(mPreference.isVisible()).isFalse();
+        assertThat(mPreference.getSummary()).isEqualTo(
+                mContext.getText(R.string.media_out_summary_ongoing_call_state));
     }
 
     /**
-     * Both hearing aid profile and A2dp Bluetooth devices are available, and two hearing aid
-     * profile devices with different HisyncId. One of HAP device is active.
-     * Preference should be visible
-     * Preference summary should be the activated device name
-     * ConnectedDevice should contain both HAP device with different HisyncId
+     * Media stream is captured by something else (cast device):
+     * Preference should be invisible
+     * Preference summary should be "unavailable"
      */
     @Test
-    public void updateState_hapBtDeviceWithDifferentId_shouldSetActivatedDeviceName() {
-        mAudioManager.setMode(AudioManager.MODE_NORMAL);
-        mShadowAudioManager.setOutputDevice(DEVICE_OUT_HEARING_AID);
-        mProfileConnectedDevices.clear();
-        mProfileConnectedDevices.add(mBluetoothDevice);
-        mProfileConnectedDevices.add(mLeftBluetoothHapDevice);
-        mProfileConnectedDevices.add(mRightBluetoothHapDevice);
-        mHearingAidActiveDevices.clear();
-        mHearingAidActiveDevices.add(null);
-        mHearingAidActiveDevices.add(mRightBluetoothHapDevice);
-        when(mHearingAidProfile.getConnectedDevices()).thenReturn(mProfileConnectedDevices);
-        when(mHearingAidProfile.getActiveDevices()).thenReturn(mHearingAidActiveDevices);
-        when(mHearingAidProfile.getHiSyncId(mLeftBluetoothHapDevice)).thenReturn(HISYNCID1);
-        when(mHearingAidProfile.getHiSyncId(mRightBluetoothHapDevice)).thenReturn(HISYNCID2);
+    public void updateState_mediaStreamIsCapturedByCast_shouldDisableAndSetDefaultSummary() {
+        mShadowAudioManager.setOutputDevice(DEVICE_OUT_REMOTE_SUBMIX);
 
         mController.updateState(mPreference);
 
-        assertThat(mPreference.isVisible()).isTrue();
-        assertThat(mPreference.getSummary()).isEqualTo(mRightBluetoothHapDevice.getName());
-        assertThat(mController.mConnectedDevices).containsExactly(mBluetoothDevice,
-                mLeftBluetoothHapDevice, mRightBluetoothHapDevice);
+        assertThat(mPreference.isVisible()).isFalse();
+        String defaultString = mContext.getString(R.string.media_output_summary_unavailable);
+        assertThat(mPreference.getSummary()).isEqualTo(defaultString);
     }
 
     @Test