blob: 6ceac131ed4b3ce3c915728046df2d5c9bc20e3d [file] [log] [blame]
/*
* 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.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Notification;
import android.content.Context;
import android.graphics.drawable.Icon;
import android.media.MediaDescription;
import android.media.MediaMetadata;
import android.media.RoutingSessionInfo;
import android.media.session.MediaController;
import android.media.session.MediaSessionManager;
import android.service.notification.StatusBarNotification;
import android.testing.AndroidTestingRunner;
import android.text.TextUtils;
import androidx.core.graphics.drawable.IconCompat;
import androidx.test.filters.SmallTest;
import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.media.LocalMediaManager;
import com.android.settingslib.media.MediaDevice;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
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)
public class MediaOutputControllerTest extends SysuiTestCase {
private static final String TEST_PACKAGE_NAME = "com.test.package.name";
private static final String TEST_DEVICE_1_ID = "test_device_1_id";
private static final String TEST_DEVICE_2_ID = "test_device_2_id";
private static final String TEST_DEVICE_3_ID = "test_device_3_id";
private static final String TEST_DEVICE_4_ID = "test_device_4_id";
private static final String TEST_DEVICE_5_ID = "test_device_5_id";
private static final String TEST_ARTIST = "test_artist";
private static final String TEST_SONG = "test_song";
private static final String TEST_SESSION_ID = "test_session_id";
private static final String TEST_SESSION_NAME = "test_session_name";
// Mock
private MediaController mMediaController = mock(MediaController.class);
private MediaSessionManager mMediaSessionManager = mock(MediaSessionManager.class);
private CachedBluetoothDeviceManager mCachedBluetoothDeviceManager =
mock(CachedBluetoothDeviceManager.class);
private LocalBluetoothManager mLocalBluetoothManager = mock(LocalBluetoothManager.class);
private MediaOutputController.Callback mCb = mock(MediaOutputController.Callback.class);
private MediaDevice mMediaDevice1 = mock(MediaDevice.class);
private MediaDevice mMediaDevice2 = mock(MediaDevice.class);
private MediaMetadata mMediaMetadata = mock(MediaMetadata.class);
private RoutingSessionInfo mRemoteSessionInfo = mock(RoutingSessionInfo.class);
private ShadeController mShadeController = mock(ShadeController.class);
private ActivityStarter mStarter = mock(ActivityStarter.class);
private NotificationEntryManager mNotificationEntryManager =
mock(NotificationEntryManager.class);
private Context mSpyContext;
private MediaOutputController mMediaOutputController;
private LocalMediaManager mLocalMediaManager;
private List<MediaController> mMediaControllers = new ArrayList<>();
private List<MediaDevice> mMediaDevices = new ArrayList<>();
private MediaDescription mMediaDescription;
private List<RoutingSessionInfo> mRoutingSessionInfos = new ArrayList<>();
@Before
public void setUp() {
mSpyContext = spy(mContext);
when(mMediaController.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
mMediaControllers.add(mMediaController);
when(mMediaSessionManager.getActiveSessions(any())).thenReturn(mMediaControllers);
doReturn(mMediaSessionManager).when(mSpyContext).getSystemService(
MediaSessionManager.class);
when(mLocalBluetoothManager.getCachedDeviceManager()).thenReturn(
mCachedBluetoothDeviceManager);
mMediaOutputController = new MediaOutputController(mSpyContext, TEST_PACKAGE_NAME, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
mNotificationEntryManager);
mLocalMediaManager = spy(mMediaOutputController.mLocalMediaManager);
mMediaOutputController.mLocalMediaManager = mLocalMediaManager;
MediaDescription.Builder builder = new MediaDescription.Builder();
builder.setTitle(TEST_SONG);
builder.setSubtitle(TEST_ARTIST);
mMediaDescription = builder.build();
when(mMediaMetadata.getDescription()).thenReturn(mMediaDescription);
when(mMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
when(mMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
mMediaDevices.add(mMediaDevice1);
mMediaDevices.add(mMediaDevice2);
}
@Test
public void start_verifyLocalMediaManagerInit() {
mMediaOutputController.start(mCb);
verify(mLocalMediaManager).registerCallback(mMediaOutputController);
verify(mLocalMediaManager).startScan();
}
@Test
public void stop_verifyLocalMediaManagerDeinit() {
mMediaOutputController.start(mCb);
reset(mLocalMediaManager);
mMediaOutputController.stop();
verify(mLocalMediaManager).unregisterCallback(mMediaOutputController);
verify(mLocalMediaManager).stopScan();
}
@Test
public void start_withPackageName_verifyMediaControllerInit() {
mMediaOutputController.start(mCb);
verify(mMediaController).registerCallback(any());
}
@Test
public void start_withoutPackageName_verifyMediaControllerInit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
mNotificationEntryManager);
mMediaOutputController.start(mCb);
verify(mMediaController, never()).registerCallback(any());
}
@Test
public void stop_withPackageName_verifyMediaControllerDeinit() {
mMediaOutputController.start(mCb);
reset(mMediaController);
mMediaOutputController.stop();
verify(mMediaController).unregisterCallback(any());
}
@Test
public void stop_withoutPackageName_verifyMediaControllerDeinit() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
mNotificationEntryManager);
mMediaOutputController.start(mCb);
mMediaOutputController.stop();
verify(mMediaController, never()).unregisterCallback(any());
}
@Test
public void onDeviceListUpdate_verifyDeviceListCallback() {
mMediaOutputController.start(mCb);
reset(mCb);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
final List<MediaDevice> devices = new ArrayList<>(mMediaOutputController.getMediaDevices());
assertThat(devices.containsAll(mMediaDevices)).isTrue();
assertThat(devices.size()).isEqualTo(mMediaDevices.size());
verify(mCb).onRouteChanged();
}
@Test
public void onSelectedDeviceStateChanged_verifyCallback() {
mMediaOutputController.start(mCb);
reset(mCb);
mMediaOutputController.onSelectedDeviceStateChanged(mMediaDevice1,
LocalMediaManager.MediaDeviceState.STATE_CONNECTED);
verify(mCb).onRouteChanged();
}
@Test
public void onDeviceAttributesChanged_verifyCallback() {
mMediaOutputController.start(mCb);
reset(mCb);
mMediaOutputController.onDeviceAttributesChanged();
verify(mCb).onRouteChanged();
}
@Test
public void onRequestFailed_verifyCallback() {
mMediaOutputController.start(mCb);
reset(mCb);
mMediaOutputController.onRequestFailed(0 /* reason */);
verify(mCb).onRouteChanged();
}
@Test
public void getHeaderTitle_withoutMetadata_returnDefaultString() {
when(mMediaController.getMetadata()).thenReturn(null);
mMediaOutputController.start(mCb);
assertThat(mMediaOutputController.getHeaderTitle()).isEqualTo(
mContext.getText(R.string.controls_media_title));
}
@Test
public void getHeaderTitle_withMetadata_returnSongName() {
when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);
mMediaOutputController.start(mCb);
assertThat(mMediaOutputController.getHeaderTitle()).isEqualTo(TEST_SONG);
}
@Test
public void getHeaderSubTitle_withoutMetadata_returnNull() {
when(mMediaController.getMetadata()).thenReturn(null);
mMediaOutputController.start(mCb);
assertThat(mMediaOutputController.getHeaderSubTitle()).isNull();
}
@Test
public void getHeaderSubTitle_withMetadata_returnArtistName() {
when(mMediaController.getMetadata()).thenReturn(mMediaMetadata);
mMediaOutputController.start(mCb);
assertThat(mMediaOutputController.getHeaderSubTitle()).isEqualTo(TEST_ARTIST);
}
@Test
public void connectDevice_verifyConnect() {
mMediaOutputController.connectDevice(mMediaDevice1);
// Wait for background thread execution
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
verify(mLocalMediaManager).connectDevice(mMediaDevice1);
}
@Test
public void getActiveRemoteMediaDevice_isSystemSession_returnSession() {
when(mRemoteSessionInfo.getId()).thenReturn(TEST_SESSION_ID);
when(mRemoteSessionInfo.getName()).thenReturn(TEST_SESSION_NAME);
when(mRemoteSessionInfo.getVolumeMax()).thenReturn(100);
when(mRemoteSessionInfo.getVolume()).thenReturn(10);
when(mRemoteSessionInfo.isSystemSession()).thenReturn(false);
mRoutingSessionInfos.add(mRemoteSessionInfo);
when(mLocalMediaManager.getActiveMediaSession()).thenReturn(mRoutingSessionInfos);
assertThat(mMediaOutputController.getActiveRemoteMediaDevices()).containsExactly(
mRemoteSessionInfo);
}
@Test
public void getActiveRemoteMediaDevice_notSystemSession_returnEmpty() {
when(mRemoteSessionInfo.getId()).thenReturn(TEST_SESSION_ID);
when(mRemoteSessionInfo.getName()).thenReturn(TEST_SESSION_NAME);
when(mRemoteSessionInfo.getVolumeMax()).thenReturn(100);
when(mRemoteSessionInfo.getVolume()).thenReturn(10);
when(mRemoteSessionInfo.isSystemSession()).thenReturn(true);
mRoutingSessionInfos.add(mRemoteSessionInfo);
when(mLocalMediaManager.getActiveMediaSession()).thenReturn(mRoutingSessionInfos);
assertThat(mMediaOutputController.getActiveRemoteMediaDevices()).isEmpty();
}
@Test
public void isZeroMode_onlyFromPhoneOutput_returnTrue() {
// Multiple available devices
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_PHONE_DEVICE);
mMediaDevices.clear();
mMediaDevices.add(mMediaDevice1);
mMediaOutputController.start(mCb);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_3POINT5_MM_AUDIO_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_USB_C_AUDIO_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isTrue();
}
@Test
public void isZeroMode_notFromPhoneOutput_returnFalse() {
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_UNKNOWN);
mMediaDevices.clear();
mMediaDevices.add(mMediaDevice1);
mMediaOutputController.start(mCb);
mMediaOutputController.onDeviceListUpdate(mMediaDevices);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_FAST_PAIR_BLUETOOTH_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_BLUETOOTH_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_CAST_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
when(mMediaDevice1.getDeviceType()).thenReturn(
MediaDevice.MediaDeviceType.TYPE_CAST_GROUP_DEVICE);
assertThat(mMediaOutputController.isZeroMode()).isFalse();
}
@Test
public void getGroupMediaDevices_differentDeviceOrder_showingSameOrder() {
final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class);
final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class);
final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class);
final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class);
final List<MediaDevice> selectedMediaDevices = new ArrayList<>();
final List<MediaDevice> selectableMediaDevices = new ArrayList<>();
when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID);
when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID);
selectedMediaDevices.add(selectedMediaDevice1);
selectedMediaDevices.add(selectedMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
selectableMediaDevices.add(selectableMediaDevice2);
doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
final List<MediaDevice> groupMediaDevices = mMediaOutputController.getGroupMediaDevices();
// Reset order
selectedMediaDevices.clear();
selectedMediaDevices.add(selectedMediaDevice2);
selectedMediaDevices.add(selectedMediaDevice1);
selectableMediaDevices.clear();
selectableMediaDevices.add(selectableMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
final List<MediaDevice> newDevices = mMediaOutputController.getGroupMediaDevices();
assertThat(newDevices.size()).isEqualTo(groupMediaDevices.size());
for (int i = 0; i < groupMediaDevices.size(); i++) {
assertThat(TextUtils.equals(groupMediaDevices.get(i).getId(),
newDevices.get(i).getId())).isTrue();
}
}
@Test
public void getGroupMediaDevices_newDevice_verifyDeviceOrder() {
final MediaDevice selectedMediaDevice1 = mock(MediaDevice.class);
final MediaDevice selectedMediaDevice2 = mock(MediaDevice.class);
final MediaDevice selectableMediaDevice1 = mock(MediaDevice.class);
final MediaDevice selectableMediaDevice2 = mock(MediaDevice.class);
final MediaDevice selectableMediaDevice3 = mock(MediaDevice.class);
final List<MediaDevice> selectedMediaDevices = new ArrayList<>();
final List<MediaDevice> selectableMediaDevices = new ArrayList<>();
when(selectedMediaDevice1.getId()).thenReturn(TEST_DEVICE_1_ID);
when(selectedMediaDevice2.getId()).thenReturn(TEST_DEVICE_2_ID);
when(selectableMediaDevice1.getId()).thenReturn(TEST_DEVICE_3_ID);
when(selectableMediaDevice2.getId()).thenReturn(TEST_DEVICE_4_ID);
when(selectableMediaDevice3.getId()).thenReturn(TEST_DEVICE_5_ID);
selectedMediaDevices.add(selectedMediaDevice1);
selectedMediaDevices.add(selectedMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
selectableMediaDevices.add(selectableMediaDevice2);
doReturn(selectedMediaDevices).when(mLocalMediaManager).getSelectedMediaDevice();
doReturn(selectableMediaDevices).when(mLocalMediaManager).getSelectableMediaDevice();
final List<MediaDevice> groupMediaDevices = mMediaOutputController.getGroupMediaDevices();
// Reset order
selectedMediaDevices.clear();
selectedMediaDevices.add(selectedMediaDevice2);
selectedMediaDevices.add(selectedMediaDevice1);
selectableMediaDevices.clear();
selectableMediaDevices.add(selectableMediaDevice3);
selectableMediaDevices.add(selectableMediaDevice2);
selectableMediaDevices.add(selectableMediaDevice1);
final List<MediaDevice> newDevices = mMediaOutputController.getGroupMediaDevices();
assertThat(newDevices.size()).isEqualTo(5);
for (int i = 0; i < groupMediaDevices.size(); i++) {
assertThat(TextUtils.equals(groupMediaDevices.get(i).getId(),
newDevices.get(i).getId())).isTrue();
}
assertThat(newDevices.get(4).getId()).isEqualTo(TEST_DEVICE_5_ID);
}
@Test
public void getNotificationLargeIcon_withoutPackageName_returnsNull() {
mMediaOutputController = new MediaOutputController(mSpyContext, null, false,
mMediaSessionManager, mLocalBluetoothManager, mShadeController, mStarter,
mNotificationEntryManager);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
@Test
public void getNotificationLargeIcon_withPackageNameAndMediaSession_returnsIconCompat() {
final List<NotificationEntry> entryList = new ArrayList<>();
final NotificationEntry entry = mock(NotificationEntry.class);
final StatusBarNotification sbn = mock(StatusBarNotification.class);
final Notification notification = mock(Notification.class);
final Icon icon = mock(Icon.class);
entryList.add(entry);
when(mNotificationEntryManager.getActiveNotificationsForCurrentUser())
.thenReturn(entryList);
when(entry.getSbn()).thenReturn(sbn);
when(sbn.getNotification()).thenReturn(notification);
when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
when(notification.hasMediaSession()).thenReturn(true);
when(notification.getLargeIcon()).thenReturn(icon);
assertThat(mMediaOutputController.getNotificationIcon() instanceof IconCompat).isTrue();
}
@Test
public void getNotificationLargeIcon_withPackageNameAndNoMediaSession_returnsNull() {
final List<NotificationEntry> entryList = new ArrayList<>();
final NotificationEntry entry = mock(NotificationEntry.class);
final StatusBarNotification sbn = mock(StatusBarNotification.class);
final Notification notification = mock(Notification.class);
final Icon icon = mock(Icon.class);
entryList.add(entry);
when(mNotificationEntryManager.getActiveNotificationsForCurrentUser())
.thenReturn(entryList);
when(entry.getSbn()).thenReturn(sbn);
when(sbn.getNotification()).thenReturn(notification);
when(sbn.getPackageName()).thenReturn(TEST_PACKAGE_NAME);
when(notification.hasMediaSession()).thenReturn(false);
when(notification.getLargeIcon()).thenReturn(icon);
assertThat(mMediaOutputController.getNotificationIcon()).isNull();
}
}