From 6feb55546dac126c10b402a1c187e0af7d04b39f Mon Sep 17 00:00:00 2001 From: hughchen Date: Tue, 12 Mar 2019 17:17:23 +0800 Subject: [PATCH] Sound + Output Switcher on Volume Slice - Show "play media to" item when Previously Connected device is available - Click "Play media to" to launch output slice - Update test case Bug: 127729340 Test: make -j50 RunSettingsRoboTests Change-Id: Ic00b309f87bc16f540b22b5a43fecb86f76caeb2 --- .../media/MediaOutputIndicatorSlice.java | 104 +++++++++++ .../media/MediaOutputIndicatorWorker.java | 161 ++++++++++++++++++ .../android/settings/panel/VolumePanel.java | 2 + .../settings/slices/CustomSliceRegistry.java | 13 +- .../media/MediaOutputIndicatorSliceTest.java | 109 ++++++++++++ .../media/MediaOutputIndicatorWorkerTest.java | 161 ++++++++++++++++++ .../settings/panel/VolumePanelTest.java | 1 + 7 files changed, 550 insertions(+), 1 deletion(-) create mode 100644 src/com/android/settings/media/MediaOutputIndicatorSlice.java create mode 100644 src/com/android/settings/media/MediaOutputIndicatorWorker.java create mode 100644 tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java create mode 100644 tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java diff --git a/src/com/android/settings/media/MediaOutputIndicatorSlice.java b/src/com/android/settings/media/MediaOutputIndicatorSlice.java new file mode 100644 index 00000000000..eb0c81f1c2c --- /dev/null +++ b/src/com/android/settings/media/MediaOutputIndicatorSlice.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2019 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.settings.media; + +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.net.Uri; + +import androidx.annotation.VisibleForTesting; +import androidx.core.graphics.drawable.IconCompat; +import androidx.slice.Slice; +import androidx.slice.builders.ListBuilder; +import androidx.slice.builders.SliceAction; + +import com.android.settings.R; +import com.android.settings.Utils; +import com.android.settings.slices.CustomSliceable; +import com.android.settings.slices.SliceBackgroundWorker; +import com.android.settingslib.media.MediaOutputSliceConstants; + +public class MediaOutputIndicatorSlice implements CustomSliceable { + + private Context mContext; + @VisibleForTesting + MediaOutputIndicatorWorker mWorker; + + public MediaOutputIndicatorSlice(Context context) { + mContext = context; + } + + @Override + public Slice getSlice() { + if (!getWorker().isVisible()) { + return null; + } + final IconCompat icon = IconCompat.createWithResource(mContext, + com.android.internal.R.drawable.ic_settings_bluetooth); + final CharSequence title = mContext.getText(R.string.media_output_title); + final PendingIntent primaryActionIntent = PendingIntent.getActivity(mContext, + 0 /* requestCode */, getMediaOutputSliceIntent(), 0 /* flags */); + final SliceAction primarySliceAction = SliceAction.createDeeplink( + primaryActionIntent, icon, ListBuilder.ICON_IMAGE, title); + @ColorInt final int color = Utils.getColorAccentDefaultColor(mContext); + + final ListBuilder listBuilder = new ListBuilder(mContext, + MEDIA_OUTPUT_INDICATOR_SLICE_URI, + ListBuilder.INFINITY) + .setAccentColor(color) + .addRow(new ListBuilder.RowBuilder() + .setTitle(title) + .setSubtitle(getWorker().findActiveDeviceName()) + .setPrimaryAction(primarySliceAction)); + return listBuilder.build(); + } + + private MediaOutputIndicatorWorker getWorker() { + if (mWorker == null) { + mWorker = (MediaOutputIndicatorWorker) SliceBackgroundWorker.getInstance(getUri()); + } + return mWorker; + } + + private Intent getMediaOutputSliceIntent() { + final Intent intent = new Intent() + .setAction(MediaOutputSliceConstants.ACTION_MEDIA_OUTPUT) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + return intent; + } + + @Override + public Uri getUri() { + return MEDIA_OUTPUT_INDICATOR_SLICE_URI; + } + + @Override + public Intent getIntent() { + // This Slice reflects active media device information and launch MediaOutputSlice. It does + // not contain its owned Slice data + return null; + } + + @Override + public Class getBackgroundWorkerClass() { + return MediaOutputIndicatorWorker.class; + } +} diff --git a/src/com/android/settings/media/MediaOutputIndicatorWorker.java b/src/com/android/settings/media/MediaOutputIndicatorWorker.java new file mode 100644 index 00000000000..adee0557be9 --- /dev/null +++ b/src/com/android/settings/media/MediaOutputIndicatorWorker.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 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.settings.media; + +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothProfile; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; +import com.android.settings.R; +import com.android.settings.bluetooth.Utils; +import com.android.settings.slices.SliceBackgroundWorker; +import com.android.settingslib.bluetooth.A2dpProfile; +import com.android.settingslib.bluetooth.BluetoothCallback; +import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.HearingAidProfile; +import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * Listener for background change from {@code BluetoothCallback} to update media output indicator. + */ +public class MediaOutputIndicatorWorker extends SliceBackgroundWorker implements BluetoothCallback { + + private static final String TAG = "MediaOutputIndicatorWorker"; + + private LocalBluetoothManager mLocalBluetoothManager; + private LocalBluetoothProfileManager mProfileManager; + + public MediaOutputIndicatorWorker(Context context, Uri uri) { + super(context, uri); + } + + @Override + protected void onSlicePinned() { + LocalBluetoothManager mLocalBluetoothManager = Utils.getLocalBtManager(getContext()); + if (mLocalBluetoothManager == null) { + Log.e(TAG, "Bluetooth is not supported on this device"); + return; + } + mProfileManager = mLocalBluetoothManager.getProfileManager(); + mLocalBluetoothManager.getEventManager().registerCallback(this); + } + + @Override + protected void onSliceUnpinned() { + if (mLocalBluetoothManager == null) { + Log.e(TAG, "Bluetooth is not supported on this device"); + return; + } + mLocalBluetoothManager.getEventManager().unregisterCallback(this); + } + + @Override + public void close() throws IOException { + mLocalBluetoothManager = null; + mProfileManager = null; + } + + @Override + public void onBluetoothStateChanged(int bluetoothState) { + // To handle the case that Bluetooth on and no connected devices + notifySliceChange(); + } + + @Override + public void onActiveDeviceChanged(CachedBluetoothDevice activeDevice, int bluetoothProfile) { + if (bluetoothProfile == BluetoothProfile.A2DP) { + notifySliceChange(); + } + } + + /** + * To decide Slice's visibility. + * + * @return true if device is connected or previously connected, false for other cases. + */ + public boolean isVisible() { + return !CollectionUtils.isEmpty(getConnectableA2dpDevices()) + || !CollectionUtils.isEmpty(getConnectableHearingAidDevices()); + } + + private List getConnectableA2dpDevices() { + // get A2dp devices on all states + // (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING) + final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + if (a2dpProfile == null) { + return new ArrayList<>(); + } + return a2dpProfile.getConnectableDevices(); + } + + private List getConnectableHearingAidDevices() { + // get hearing aid profile devices on all states + // (STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED, STATE_DISCONNECTING) + final HearingAidProfile hapProfile = mProfileManager.getHearingAidProfile(); + if (hapProfile == null) { + return new ArrayList<>(); + } + + return hapProfile.getConnectableDevices(); + } + + /** + * Get active devices name. + * + * @return active Bluetooth device alias, or default summary if no active device. + */ + public CharSequence findActiveDeviceName() { + // Return Hearing Aid device name if it is active + BluetoothDevice activeDevice = findActiveHearingAidDevice(); + if (activeDevice != null) { + return activeDevice.getAliasName(); + } + // Return A2DP device name if it is active + final A2dpProfile a2dpProfile = mProfileManager.getA2dpProfile(); + if (a2dpProfile != null) { + activeDevice = a2dpProfile.getActiveDevice(); + if (activeDevice != null) { + return activeDevice.getAliasName(); + } + } + // No active device, return default summary + return getContext().getText(R.string.media_output_default_summary); + } + + private BluetoothDevice findActiveHearingAidDevice() { + final HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile(); + if (hearingAidProfile == null) { + return null; + } + + final List activeDevices = hearingAidProfile.getActiveDevices(); + for (BluetoothDevice btDevice : activeDevices) { + if (btDevice != null) { + return btDevice; + } + } + return null; + } +} diff --git a/src/com/android/settings/panel/VolumePanel.java b/src/com/android/settings/panel/VolumePanel.java index 62eca53898b..4ea7fe7561b 100644 --- a/src/com/android/settings/panel/VolumePanel.java +++ b/src/com/android/settings/panel/VolumePanel.java @@ -16,6 +16,7 @@ package com.android.settings.panel; +import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; import static com.android.settings.slices.CustomSliceRegistry.VOLUME_ALARM_URI; import static com.android.settings.slices.CustomSliceRegistry.VOLUME_CALL_URI; import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI; @@ -55,6 +56,7 @@ public class VolumePanel implements PanelContent { final List uris = new ArrayList<>(); uris.add(VOLUME_REMOTE_MEDIA_URI); uris.add(VOLUME_MEDIA_URI); + uris.add(MEDIA_OUTPUT_INDICATOR_SLICE_URI); uris.add(VOLUME_CALL_URI); uris.add(VOLUME_RINGER_URI); uris.add(VOLUME_ALARM_URI); diff --git a/src/com/android/settings/slices/CustomSliceRegistry.java b/src/com/android/settings/slices/CustomSliceRegistry.java index 12e7b48ffb2..3c9b17b35b1 100644 --- a/src/com/android/settings/slices/CustomSliceRegistry.java +++ b/src/com/android/settings/slices/CustomSliceRegistry.java @@ -39,6 +39,7 @@ import com.android.settings.homepage.contextualcards.slices.BluetoothDevicesSlic import com.android.settings.homepage.contextualcards.slices.LowStorageSlice; import com.android.settings.homepage.contextualcards.slices.NotificationChannelSlice; import com.android.settings.location.LocationSlice; +import com.android.settings.media.MediaOutputIndicatorSlice; import com.android.settings.media.MediaOutputSlice; import com.android.settings.network.telephony.MobileDataSlice; import com.android.settings.wifi.calling.WifiCallingSliceHelper; @@ -299,6 +300,16 @@ public class CustomSliceRegistry { .appendPath(MediaOutputSliceConstants.KEY_MEDIA_OUTPUT) .build(); + /** + * Backing Uri for the Media output indicator Slice. + */ + public static Uri MEDIA_OUTPUT_INDICATOR_SLICE_URI = new Uri.Builder() + .scheme(ContentResolver.SCHEME_CONTENT) + .authority(SettingsSliceProvider.SLICE_AUTHORITY) + .appendPath(SettingsSlicesContract.PATH_SETTING_INTENT) + .appendPath("media_output_indicator") + .build(); + @VisibleForTesting static final Map> sUriToSlice; @@ -319,6 +330,7 @@ public class CustomSliceRegistry { sUriToSlice.put(STORAGE_SLICE_URI, StorageSlice.class); sUriToSlice.put(WIFI_SLICE_URI, WifiSlice.class); sUriToSlice.put(MEDIA_OUTPUT_SLICE_URI, MediaOutputSlice.class); + sUriToSlice.put(MEDIA_OUTPUT_INDICATOR_SLICE_URI, MediaOutputIndicatorSlice.class); } public static Class getSliceClassByUri(Uri uri) { @@ -344,5 +356,4 @@ public class CustomSliceRegistry { public static boolean isValidAction(String action) { return isValidUri(Uri.parse(action)); } - } diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java new file mode 100644 index 00000000000..ab3f4de26f9 --- /dev/null +++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorSliceTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2019 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.settings.media; + +import static com.android.settings.slices.CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.content.Context; +import android.content.Intent; + +import androidx.slice.Slice; +import androidx.slice.SliceItem; +import androidx.slice.SliceMetadata; +import androidx.slice.SliceProvider; +import androidx.slice.core.SliceAction; +import androidx.slice.widget.SliceLiveData; + +import com.android.settings.R; +import com.android.settings.testutils.shadow.ShadowBluetoothAdapter; +import com.android.settingslib.media.LocalMediaManager; +import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.media.MediaOutputSliceConstants; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothAdapter.class}) +public class MediaOutputIndicatorSliceTest { + + private static final String TEST_DEVICE_NAME = "test_device_name"; + private static final int TEST_DEVICE_1_ICON = + com.android.internal.R.drawable.ic_bt_headphones_a2dp; + + @Mock + private LocalMediaManager mLocalMediaManager; + + private final List mDevices = new ArrayList<>(); + + private Context mContext; + private MediaOutputIndicatorSlice mMediaOutputIndicatorSlice; + private MediaOutputIndicatorWorker mMediaOutputIndicatorWorker; + private ShadowBluetoothAdapter mShadowBluetoothAdapter; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + + // Set-up specs for SliceMetadata. + SliceProvider.setSpecs(SliceLiveData.SUPPORTED_SPECS); + + mMediaOutputIndicatorSlice = new MediaOutputIndicatorSlice(mContext); + mMediaOutputIndicatorWorker = spy(new MediaOutputIndicatorWorker( + mContext, MEDIA_OUTPUT_INDICATOR_SLICE_URI)); + mMediaOutputIndicatorSlice.mWorker = mMediaOutputIndicatorWorker; + } + + @Test + public void getSlice_invisible_returnNull() { + when(mMediaOutputIndicatorWorker.isVisible()).thenReturn(false); + + assertThat(mMediaOutputIndicatorSlice.getSlice()).isNull(); + } + + @Test + public void getSlice_withActiveDevice_checkContent() { + when(mMediaOutputIndicatorWorker.isVisible()).thenReturn(true); + when(mMediaOutputIndicatorWorker.findActiveDeviceName()).thenReturn(TEST_DEVICE_NAME); + final Slice mediaSlice = mMediaOutputIndicatorSlice.getSlice(); + final SliceMetadata metadata = SliceMetadata.from(mContext, mediaSlice); + // Verify slice title and subtitle + assertThat(metadata.getTitle()).isEqualTo(mContext.getText(R.string.media_output_title)); + assertThat(metadata.getSubtitle()).isEqualTo(TEST_DEVICE_NAME); + } +} diff --git a/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java new file mode 100644 index 00000000000..4a5662e53de --- /dev/null +++ b/tests/robotests/src/com/android/settings/media/MediaOutputIndicatorWorkerTest.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2019 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.settings.media; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.content.Context; +import android.net.Uri; + +import com.android.settings.R; +import com.android.settings.bluetooth.Utils; +import com.android.settings.testutils.shadow.ShadowBluetoothUtils; +import com.android.settingslib.bluetooth.A2dpProfile; +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 org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowBluetoothDevice; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowBluetoothUtils.class, + ShadowBluetoothDevice.class}) +public class MediaOutputIndicatorWorkerTest { + + private static final String TEST_A2DP_DEVICE_NAME = "Test_A2DP_BT_Device_NAME"; + private static final String TEST_HAP_DEVICE_NAME = "Test_HAP_BT_Device_NAME"; + private static final String TEST_A2DP_DEVICE_ADDRESS = "00:A1:A1:A1:A1:A1"; + private static final String TEST_HAP_DEVICE_ADDRESS = "00:B2:B2:B2:B2:B2"; + private static final Uri URI = Uri.parse("content://com.android.settings.slices/test"); + + @Mock + private A2dpProfile mA2dpProfile; + @Mock + private HearingAidProfile mHearingAidProfile; + @Mock + private LocalBluetoothManager mLocalManager; + @Mock + private BluetoothEventManager mBluetoothEventManager; + @Mock + private LocalBluetoothProfileManager mLocalBluetoothProfileManager; + + private BluetoothAdapter mBluetoothAdapter; + private BluetoothDevice mA2dpDevice; + private BluetoothDevice mHapDevice; + private BluetoothManager mBluetoothManager; + private Context mContext; + private List mDevicesList; + private LocalBluetoothManager mLocalBluetoothManager; + private MediaOutputIndicatorWorker mMediaDeviceUpdateWorker; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + ShadowBluetoothUtils.sLocalBluetoothManager = mLocalManager; + mLocalBluetoothManager = Utils.getLocalBtManager(mContext); + when(mLocalBluetoothManager.getEventManager()).thenReturn(mBluetoothEventManager); + when(mLocalBluetoothManager.getProfileManager()).thenReturn(mLocalBluetoothProfileManager); + when(mLocalBluetoothProfileManager.getA2dpProfile()).thenReturn(mA2dpProfile); + when(mLocalBluetoothProfileManager.getHearingAidProfile()).thenReturn(mHearingAidProfile); + mBluetoothManager = new BluetoothManager(mContext); + mBluetoothAdapter = mBluetoothManager.getAdapter(); + + // Setup A2dp device + mA2dpDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_A2DP_DEVICE_ADDRESS)); + when(mA2dpDevice.getName()).thenReturn(TEST_A2DP_DEVICE_NAME); + when(mA2dpDevice.isConnected()).thenReturn(true); + // Setup HearingAid device + mHapDevice = spy(mBluetoothAdapter.getRemoteDevice(TEST_HAP_DEVICE_ADDRESS)); + when(mHapDevice.getName()).thenReturn(TEST_HAP_DEVICE_NAME); + when(mHapDevice.isConnected()).thenReturn(true); + + mMediaDeviceUpdateWorker = new MediaOutputIndicatorWorker(mContext, URI); + mDevicesList = new ArrayList<>(); + } + + @Test + public void isVisible_noConnectableDevice_returnFalse() { + mDevicesList.clear(); + when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList); + + assertThat(mMediaDeviceUpdateWorker.isVisible()).isFalse(); + } + + @Test + public void isVisible_withConnectableA2dpDevice_returnTrue() { + mDevicesList.clear(); + mDevicesList.add(mA2dpDevice); + when(mHearingAidProfile.getConnectableDevices()).thenReturn(mDevicesList); + + assertThat(mMediaDeviceUpdateWorker.isVisible()).isTrue(); + } + + @Test + public void isVisible_withConnectableHADevice_returnTrue() { + mDevicesList.clear(); + mDevicesList.add(mHapDevice); + when(mA2dpProfile.getConnectableDevices()).thenReturn(mDevicesList); + + assertThat(mMediaDeviceUpdateWorker.isVisible()).isTrue(); + } + + @Test + public void findActiveDeviceName_A2dpDeviceActive_verifyName() { + when(mA2dpProfile.getActiveDevice()).thenReturn(mA2dpDevice); + + assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName()) + .isEqualTo(mA2dpDevice.getAliasName()); + } + + @Test + public void findActiveDeviceName_HADeviceActive_verifyName() { + mDevicesList.add(mHapDevice); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList); + + assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName()) + .isEqualTo(mHapDevice.getAliasName()); + } + + @Test + public void findActiveDeviceName_noActiveDevice_verifyDefaultName() { + when(mA2dpProfile.getActiveDevice()).thenReturn(null); + mDevicesList.clear(); + when(mHearingAidProfile.getActiveDevices()).thenReturn(mDevicesList); + + assertThat(mMediaDeviceUpdateWorker.findActiveDeviceName()) + .isEqualTo(mContext.getText(R.string.media_output_default_summary)); + } +} diff --git a/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java index 4665dc9b4fd..11de7b31b60 100644 --- a/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java +++ b/tests/robotests/src/com/android/settings/panel/VolumePanelTest.java @@ -48,6 +48,7 @@ public class VolumePanelTest { CustomSliceRegistry.VOLUME_REMOTE_MEDIA_URI, CustomSliceRegistry.VOLUME_CALL_URI, CustomSliceRegistry.VOLUME_MEDIA_URI, + CustomSliceRegistry.MEDIA_OUTPUT_INDICATOR_SLICE_URI, CustomSliceRegistry.VOLUME_RINGER_URI, CustomSliceRegistry.VOLUME_ALARM_URI); }