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.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.mock; 22 import static org.mockito.Mockito.spy; 23 import static org.mockito.Mockito.when; 24 25 import android.content.Context; 26 import android.content.res.Resources; 27 import android.media.AudioManager; 28 import android.os.Vibrator; 29 import android.provider.DeviceConfig; 30 import android.service.notification.NotificationListenerService; 31 import android.telephony.TelephonyManager; 32 33 import androidx.preference.PreferenceManager; 34 import androidx.preference.PreferenceScreen; 35 import androidx.test.core.app.ApplicationProvider; 36 37 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags; 38 import com.android.settings.core.BasePreferenceController; 39 import com.android.settings.testutils.shadow.ShadowDeviceConfig; 40 41 import org.junit.Before; 42 import org.junit.Test; 43 import org.junit.runner.RunWith; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 import org.robolectric.RobolectricTestRunner; 47 import org.robolectric.RuntimeEnvironment; 48 import org.robolectric.Shadows; 49 import org.robolectric.annotation.Config; 50 51 @RunWith(RobolectricTestRunner.class) 52 @Config(shadows = {ShadowDeviceConfig.class}) 53 public class NotificationVolumePreferenceControllerTest { 54 @Mock 55 private AudioHelper mHelper; 56 @Mock 57 private TelephonyManager mTelephonyManager; 58 @Mock 59 private AudioManager mAudioManager; 60 @Mock 61 private Vibrator mVibrator; 62 @Mock 63 private Resources mResources; 64 @Mock 65 private PreferenceManager mPreferenceManager; 66 67 private static final String READ_DEVICE_CONFIG_PERMISSION = 68 "android.permission.READ_DEVICE_CONFIG"; 69 70 private Context mContext; 71 private NotificationVolumePreferenceController mController; 72 73 @Before setUp()74 public void setUp() { 75 MockitoAnnotations.initMocks(this); 76 mContext = spy(RuntimeEnvironment.application); 77 when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephonyManager); 78 when(mContext.getSystemService(Context.AUDIO_SERVICE)).thenReturn(mAudioManager); 79 when(mContext.getSystemService(Context.VIBRATOR_SERVICE)).thenReturn(mVibrator); 80 when(mContext.getResources()).thenReturn(mResources); 81 82 mController = new NotificationVolumePreferenceController(mContext); 83 mController.setAudioHelper(mHelper); 84 } 85 86 @Test 87 @Config(qualifiers = "mcc999") isAvailable_whenNotVisible_shouldReturnFalse()88 public void isAvailable_whenNotVisible_shouldReturnFalse() { 89 assertThat(mController.isAvailable()).isFalse(); 90 } 91 92 @Test isAvailable_singleVolume_shouldReturnFalse()93 public void isAvailable_singleVolume_shouldReturnFalse() { 94 when(mHelper.isSingleVolume()).thenReturn(true); 95 when(mTelephonyManager.isVoiceCapable()).thenReturn(false); 96 97 assertThat(mController.isAvailable()).isFalse(); 98 } 99 100 @Test isAvailable_voiceCapable_aliasedWithRing_shouldReturnFalse()101 public void isAvailable_voiceCapable_aliasedWithRing_shouldReturnFalse() { 102 when(mResources.getBoolean( 103 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 104 105 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 106 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); 107 108 NotificationVolumePreferenceController controller = 109 new NotificationVolumePreferenceController(mContext); 110 when(mHelper.isSingleVolume()).thenReturn(false); 111 when(mTelephonyManager.isVoiceCapable()).thenReturn(true); 112 113 assertThat(controller.isAvailable()).isFalse(); 114 } 115 116 /** 117 * With the introduction of ring-notification volume separation, voice-capable devices could now 118 * display the notification volume slider. 119 */ 120 @Test isAvailable_voiceCapable_separatedFromRing_shouldReturnTrue()121 public void isAvailable_voiceCapable_separatedFromRing_shouldReturnTrue() { 122 when(mResources.getBoolean( 123 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 124 125 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 126 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); 127 128 NotificationVolumePreferenceController controller = 129 new NotificationVolumePreferenceController(mContext); 130 131 when(mHelper.isSingleVolume()).thenReturn(false); 132 when(mTelephonyManager.isVoiceCapable()).thenReturn(true); 133 134 assertThat(controller.isAvailable()).isTrue(); 135 } 136 137 @Test isAvailable_notShowNotificationVolume_shouldReturnFalse()138 public void isAvailable_notShowNotificationVolume_shouldReturnFalse() { 139 when(mResources.getBoolean( 140 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(false); 141 142 assertThat(mController.isAvailable()).isFalse(); 143 } 144 145 @Test isAvailable_notSingleVolume_notVoiceCapable_shouldReturnTrue()146 public void isAvailable_notSingleVolume_notVoiceCapable_shouldReturnTrue() { 147 when(mResources.getBoolean( 148 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 149 when(mHelper.isSingleVolume()).thenReturn(false); 150 when(mTelephonyManager.isVoiceCapable()).thenReturn(false); 151 152 assertThat(mController.isAvailable()).isTrue(); 153 } 154 155 @Test getAudioStream_shouldReturnNotification()156 public void getAudioStream_shouldReturnNotification() { 157 assertThat(mController.getAudioStream()).isEqualTo(AudioManager.STREAM_NOTIFICATION); 158 } 159 160 @Test isSliceableCorrectKey_returnsTrue()161 public void isSliceableCorrectKey_returnsTrue() { 162 final NotificationVolumePreferenceController controller = 163 new NotificationVolumePreferenceController(mContext); 164 assertThat(controller.isSliceable()).isTrue(); 165 } 166 167 @Test isPublicSlice_returnTrue()168 public void isPublicSlice_returnTrue() { 169 assertThat(mController.isPublicSlice()).isTrue(); 170 } 171 172 @Test setHintsRing_DoesNotMatch()173 public void setHintsRing_DoesNotMatch() { 174 assertThat(mController.hintsMatch( 175 NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS)).isFalse(); 176 } 177 178 @Test setHintsAll_Matches()179 public void setHintsAll_Matches() { 180 assertThat(mController.hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_EFFECTS)) 181 .isTrue(); 182 } 183 184 @Test setHintNotification_Matches()185 public void setHintNotification_Matches() { 186 assertThat(mController 187 .hintsMatch(NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS)) 188 .isTrue(); 189 } 190 191 @Test enableSeparateNotificationConfig_controllerBecomesAvailable()192 public void enableSeparateNotificationConfig_controllerBecomesAvailable() { 193 PreferenceScreen screen = spy(new PreferenceScreen(mContext, null)); 194 VolumeSeekBarPreference volumeSeekBarPreference = mock(VolumeSeekBarPreference.class); 195 when(screen.getPreferenceManager()).thenReturn(mPreferenceManager); 196 when(screen.getContext()).thenReturn(mContext); 197 when(mResources.getBoolean( 198 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 199 // block the alternative condition to enable controller 200 when(mTelephonyManager.isVoiceCapable()).thenReturn(true); 201 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); 202 203 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 204 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); 205 206 NotificationVolumePreferenceController controller = 207 new NotificationVolumePreferenceController(mContext); 208 when(screen.findPreference(controller.getPreferenceKey())) 209 .thenReturn(volumeSeekBarPreference); 210 211 // allow the controller to subscribe 212 Shadows.shadowOf((android.app.Application) ApplicationProvider.getApplicationContext()) 213 .grantPermissions(READ_DEVICE_CONFIG_PERMISSION); 214 controller.onResume(); 215 controller.displayPreference(screen); 216 217 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 218 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, Boolean.toString(true), 219 false); 220 221 assertThat(controller.getAvailabilityStatus()).isEqualTo( 222 BasePreferenceController.AVAILABLE); 223 } 224 225 @Test disableSeparateNotificationConfig_controllerBecomesUnavailable()226 public void disableSeparateNotificationConfig_controllerBecomesUnavailable() { 227 PreferenceScreen screen = spy(new PreferenceScreen(mContext, null)); 228 VolumeSeekBarPreference volumeSeekBarPreference = mock(VolumeSeekBarPreference.class); 229 when(screen.getPreferenceManager()).thenReturn(mPreferenceManager); 230 when(screen.getContext()).thenReturn(mContext); 231 when(mResources.getBoolean( 232 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 233 234 // block the alternative condition to enable controller 235 when(mTelephonyManager.isVoiceCapable()).thenReturn(true); 236 237 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); 238 239 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 240 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); 241 NotificationVolumePreferenceController controller = 242 new NotificationVolumePreferenceController(mContext); 243 244 when(screen.findPreference(controller.getPreferenceKey())) 245 .thenReturn(volumeSeekBarPreference); 246 247 Shadows.shadowOf((android.app.Application) ApplicationProvider.getApplicationContext()) 248 .grantPermissions(READ_DEVICE_CONFIG_PERMISSION); 249 controller.onResume(); 250 controller.displayPreference(screen); 251 252 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 253 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "false", false); 254 255 assertThat(controller.getAvailabilityStatus() 256 == BasePreferenceController.UNSUPPORTED_ON_DEVICE).isTrue(); 257 } 258 259 @Test ringerModeSilent_unaliased_getAvailability_returnsDisabled()260 public void ringerModeSilent_unaliased_getAvailability_returnsDisabled() { 261 when(mResources.getBoolean( 262 com.android.settings.R.bool.config_show_notification_volume)).thenReturn(true); 263 when(mHelper.isSingleVolume()).thenReturn(false); 264 265 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); 266 267 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI, 268 SystemUiDeviceConfigFlags.VOLUME_SEPARATE_NOTIFICATION, "true", false); 269 270 assertThat(mController.getAvailabilityStatus()) 271 .isEqualTo(BasePreferenceController.DISABLED_DEPENDENT_SETTING); 272 } 273 274 } 275