1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.settings.notification; 18 19 import static com.android.settings.slices.CustomSliceRegistry.VOLUME_MEDIA_URI; 20 21 import static com.google.common.truth.Truth.assertThat; 22 23 import static org.mockito.Mockito.doReturn; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.spy; 26 import static org.mockito.Mockito.when; 27 28 import android.app.PendingIntent; 29 import android.content.Context; 30 import android.content.Intent; 31 import android.media.AudioManager; 32 import android.media.session.MediaController; 33 import android.net.Uri; 34 import android.platform.test.annotations.RequiresFlagsDisabled; 35 import android.platform.test.annotations.RequiresFlagsEnabled; 36 import android.platform.test.flag.junit.CheckFlagsRule; 37 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 38 39 import androidx.slice.builders.SliceAction; 40 41 import com.android.settings.media.MediaOutputIndicatorWorker; 42 import com.android.settings.slices.SliceBackgroundWorker; 43 import com.android.settingslib.bluetooth.CachedBluetoothDevice; 44 import com.android.settingslib.flags.Flags; 45 import com.android.settingslib.media.BluetoothMediaDevice; 46 import com.android.settingslib.media.MediaDevice; 47 import com.android.settingslib.media.MediaOutputConstants; 48 49 import org.junit.Before; 50 import org.junit.Rule; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 import org.mockito.Mock; 54 import org.mockito.MockitoAnnotations; 55 import org.robolectric.RobolectricTestRunner; 56 import org.robolectric.RuntimeEnvironment; 57 import org.robolectric.annotation.Config; 58 import org.robolectric.annotation.Implementation; 59 import org.robolectric.annotation.Implements; 60 61 @RunWith(RobolectricTestRunner.class) 62 @Config(shadows = MediaVolumePreferenceControllerTest.ShadowSliceBackgroundWorker.class) 63 public class MediaVolumePreferenceControllerTest { 64 65 private static final String ACTION_LAUNCH_BROADCAST_DIALOG = 66 "android.settings.MEDIA_BROADCAST_DIALOG"; 67 private static MediaOutputIndicatorWorker sMediaOutputIndicatorWorker; 68 69 @Rule 70 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 71 72 private MediaVolumePreferenceController mController; 73 74 private Context mContext; 75 76 @Mock private MediaController mMediaController; 77 @Mock private MediaDevice mDevice1; 78 @Mock private MediaDevice mDevice2; 79 80 @Before setUp()81 public void setUp() { 82 MockitoAnnotations.initMocks(this); 83 84 mContext = RuntimeEnvironment.application; 85 mController = new MediaVolumePreferenceController(mContext); 86 sMediaOutputIndicatorWorker = 87 spy(new MediaOutputIndicatorWorker(mContext, VOLUME_MEDIA_URI)); 88 when(mDevice1.isBLEDevice()).thenReturn(true); 89 when(mDevice2.isBLEDevice()).thenReturn(false); 90 } 91 92 @Test isAvailable_byDefault_isTrue()93 public void isAvailable_byDefault_isTrue() { 94 assertThat(mController.isAvailable()).isTrue(); 95 } 96 97 @Test 98 @Config(qualifiers = "mcc999") isAvailable_whenNotVisible_isFalse()99 public void isAvailable_whenNotVisible_isFalse() { 100 assertThat(mController.isAvailable()).isFalse(); 101 } 102 103 @Test getAudioStream_shouldReturnMusic()104 public void getAudioStream_shouldReturnMusic() { 105 assertThat(mController.getAudioStream()).isEqualTo(AudioManager.STREAM_MUSIC); 106 } 107 108 @Test isSliceableCorrectKey_returnsTrue()109 public void isSliceableCorrectKey_returnsTrue() { 110 final MediaVolumePreferenceController controller = 111 new MediaVolumePreferenceController(mContext); 112 assertThat(controller.isSliceable()).isTrue(); 113 } 114 115 @Test isPublicSlice_returnTrue()116 public void isPublicSlice_returnTrue() { 117 assertThat(mController.isPublicSlice()).isTrue(); 118 } 119 120 @Test 121 @RequiresFlagsDisabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_flagOff_returnsFalse()122 public void isSupportEndItem_flagOff_returnsFalse() { 123 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 124 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 125 doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 126 127 assertThat(mController.isSupportEndItem()).isFalse(); 128 } 129 130 @Test 131 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_withBleDevice_returnsTrue()132 public void isSupportEndItem_withBleDevice_returnsTrue() { 133 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 134 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 135 doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 136 137 assertThat(mController.isSupportEndItem()).isTrue(); 138 } 139 140 @Test 141 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_notSupportedBroadcast_returnsFalse()142 public void isSupportEndItem_notSupportedBroadcast_returnsFalse() { 143 doReturn(false).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 144 doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 145 146 assertThat(mController.isSupportEndItem()).isFalse(); 147 } 148 149 @Test 150 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_withNonBleDevice_returnsFalse()151 public void isSupportEndItem_withNonBleDevice_returnsFalse() { 152 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 153 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 154 doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 155 156 assertThat(mController.isSupportEndItem()).isFalse(); 157 } 158 159 @Test 160 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_deviceIsBroadcastingAndConnectedToNonBleDevice_returnsTrue()161 public void isSupportEndItem_deviceIsBroadcastingAndConnectedToNonBleDevice_returnsTrue() { 162 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 163 doReturn(true).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 164 doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 165 166 assertThat(mController.isSupportEndItem()).isTrue(); 167 } 168 169 @Test 170 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) isSupportEndItem_deviceIsNotBroadcastingAndConnectedToNonBleDevice_returnsFalse()171 public void isSupportEndItem_deviceIsNotBroadcastingAndConnectedToNonBleDevice_returnsFalse() { 172 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 173 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 174 doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 175 176 assertThat(mController.isSupportEndItem()).isFalse(); 177 } 178 179 @Test 180 @RequiresFlagsDisabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) getSliceEndItem_flagOff_getsNullSliceAction()181 public void getSliceEndItem_flagOff_getsNullSliceAction() { 182 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 183 doReturn(true).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 184 doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 185 186 final SliceAction sliceAction = mController.getSliceEndItem(mContext); 187 188 assertThat(sliceAction).isNull(); 189 } 190 191 @Test 192 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) getSliceEndItem_NotSupportEndItem_getsNullSliceAction()193 public void getSliceEndItem_NotSupportEndItem_getsNullSliceAction() { 194 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 195 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 196 doReturn(mDevice2).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 197 198 final SliceAction sliceAction = mController.getSliceEndItem(mContext); 199 200 assertThat(sliceAction).isNull(); 201 } 202 203 @Test 204 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) getSliceEndItem_deviceIsBroadcasting_getsBroadcastIntent()205 public void getSliceEndItem_deviceIsBroadcasting_getsBroadcastIntent() { 206 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 207 doReturn(mDevice1).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 208 doReturn(true).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 209 doReturn(mMediaController) 210 .when(sMediaOutputIndicatorWorker) 211 .getActiveLocalMediaController(); 212 213 final SliceAction sliceAction = mController.getSliceEndItem(mContext); 214 215 final PendingIntent endItemPendingIntent = sliceAction.getAction(); 216 final PendingIntent expectedToggleIntent = 217 getBroadcastIntent( 218 MediaOutputConstants.ACTION_LAUNCH_MEDIA_OUTPUT_BROADCAST_DIALOG); 219 assertThat(endItemPendingIntent).isEqualTo(expectedToggleIntent); 220 } 221 222 @Test 223 @RequiresFlagsEnabled(Flags.FLAG_LEGACY_LE_AUDIO_SHARING) getSliceEndItem_deviceIsNotBroadcasting_getsActivityIntent()224 public void getSliceEndItem_deviceIsNotBroadcasting_getsActivityIntent() { 225 final MediaDevice device = mock(BluetoothMediaDevice.class); 226 final CachedBluetoothDevice cachedDevice = mock(CachedBluetoothDevice.class); 227 when(((BluetoothMediaDevice) device).getCachedDevice()).thenReturn(cachedDevice); 228 when(device.isBLEDevice()).thenReturn(true); 229 doReturn(true).when(sMediaOutputIndicatorWorker).isBroadcastSupported(); 230 doReturn(device).when(sMediaOutputIndicatorWorker).getCurrentConnectedMediaDevice(); 231 doReturn(false).when(sMediaOutputIndicatorWorker).isDeviceBroadcasting(); 232 doReturn(mMediaController) 233 .when(sMediaOutputIndicatorWorker) 234 .getActiveLocalMediaController(); 235 236 final SliceAction sliceAction = mController.getSliceEndItem(mContext); 237 238 final PendingIntent endItemPendingIntent = sliceAction.getAction(); 239 final PendingIntent expectedPendingIntent = 240 getActivityIntent(ACTION_LAUNCH_BROADCAST_DIALOG); 241 assertThat(endItemPendingIntent).isEqualTo(expectedPendingIntent); 242 } 243 244 @Implements(SliceBackgroundWorker.class) 245 public static class ShadowSliceBackgroundWorker { 246 247 @Implementation getInstance(Uri uri)248 public static SliceBackgroundWorker getInstance(Uri uri) { 249 return sMediaOutputIndicatorWorker; 250 } 251 } 252 getBroadcastIntent(String action)253 private PendingIntent getBroadcastIntent(String action) { 254 final Intent intent = new Intent(action); 255 intent.setPackage(MediaOutputConstants.SYSTEMUI_PACKAGE_NAME); 256 return PendingIntent.getBroadcast( 257 mContext, 258 0 /* requestCode */, 259 intent, 260 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 261 } 262 getActivityIntent(String action)263 private PendingIntent getActivityIntent(String action) { 264 final Intent intent = new Intent(action); 265 return PendingIntent.getActivity( 266 mContext, 267 0 /* requestCode */, 268 intent, 269 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); 270 } 271 } 272