1 /* 2 * Copyright (C) 2017 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 android.app.NotificationChannel.DEFAULT_CHANNEL_ID; 20 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 21 import static android.app.NotificationManager.IMPORTANCE_HIGH; 22 import static android.app.NotificationManager.IMPORTANCE_LOW; 23 import static junit.framework.Assert.assertFalse; 24 import static junit.framework.Assert.assertTrue; 25 import static org.junit.Assert.assertEquals; 26 import static org.mockito.ArgumentMatchers.any; 27 import static org.mockito.ArgumentMatchers.anyInt; 28 import static org.mockito.Mockito.mock; 29 import static org.mockito.Mockito.never; 30 import static org.mockito.Mockito.spy; 31 import static org.mockito.Mockito.times; 32 import static org.mockito.Mockito.verify; 33 import static org.mockito.Mockito.when; 34 35 import android.app.Notification; 36 import android.app.NotificationChannel; 37 import android.app.NotificationManager; 38 import android.content.Context; 39 import android.content.Intent; 40 import android.net.Uri; 41 import android.os.UserManager; 42 import android.provider.Settings; 43 import android.support.v7.preference.Preference; 44 import android.support.v7.preference.PreferenceScreen; 45 import android.util.AttributeSet; 46 47 import com.android.settings.SettingsPreferenceFragment; 48 import com.android.settings.testutils.SettingsRobolectricTestRunner; 49 import com.android.settings.testutils.shadow.SettingsShadowResources; 50 import com.android.settingslib.RestrictedLockUtils; 51 52 import org.junit.After; 53 import org.junit.Before; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 import org.mockito.Answers; 57 import org.mockito.Mock; 58 import org.mockito.MockitoAnnotations; 59 import org.robolectric.annotation.Config; 60 import org.robolectric.shadows.ShadowApplication; 61 62 @RunWith(SettingsRobolectricTestRunner.class) 63 @Config(shadows = SettingsShadowResources.class) 64 public class SoundPreferenceControllerTest { 65 66 private Context mContext; 67 @Mock 68 private NotificationBackend mBackend; 69 @Mock 70 private NotificationManager mNm; 71 @Mock 72 private UserManager mUm; 73 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 74 private PreferenceScreen mScreen; 75 @Mock 76 private SettingsPreferenceFragment mFragment; 77 @Mock 78 private NotificationSettingsBase.ImportanceListener mImportanceListener; 79 80 private SoundPreferenceController mController; 81 82 @Before setUp()83 public void setUp() { 84 MockitoAnnotations.initMocks(this); 85 ShadowApplication shadowApplication = ShadowApplication.getInstance(); 86 shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm); 87 shadowApplication.setSystemService(Context.USER_SERVICE, mUm); 88 SettingsShadowResources.overrideResource(com.android.internal.R.string.ringtone_silent, 89 "silent"); 90 mContext = shadowApplication.getApplicationContext(); 91 mController = spy(new SoundPreferenceController( 92 mContext, mFragment, mImportanceListener, mBackend)); 93 } 94 95 @After tearDown()96 public void tearDown() { 97 SettingsShadowResources.reset(); 98 } 99 100 @Test testNoCrashIfNoOnResume()101 public void testNoCrashIfNoOnResume() throws Exception { 102 mController.isAvailable(); 103 mController.updateState(mock(NotificationSoundPreference.class)); 104 mController.onPreferenceChange(mock(NotificationSoundPreference.class), Uri.EMPTY); 105 mController.handlePreferenceTreeClick(mock(NotificationSoundPreference.class)); 106 mController.onActivityResult(1, 1, null); 107 SoundPreferenceController.hasValidSound(null); 108 } 109 110 @Test testIsAvailable_notIfChannelNull()111 public void testIsAvailable_notIfChannelNull() throws Exception { 112 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 113 mController.onResume(appRow, null, null, null); 114 assertFalse(mController.isAvailable()); 115 } 116 117 @Test testIsAvailable_notIfNotImportant()118 public void testIsAvailable_notIfNotImportant() throws Exception { 119 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 120 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW); 121 mController.onResume(appRow, channel, null, null); 122 assertFalse(mController.isAvailable()); 123 } 124 125 @Test testIsAvailable_notIfDefaultChannel()126 public void testIsAvailable_notIfDefaultChannel() throws Exception { 127 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 128 NotificationChannel channel = 129 new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT); 130 mController.onResume(appRow, channel, null, null); 131 assertFalse(mController.isAvailable()); 132 } 133 134 @Test testIsAvailable()135 public void testIsAvailable() throws Exception { 136 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 137 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT); 138 mController.onResume(appRow, channel, null, null); 139 assertTrue(mController.isAvailable()); 140 } 141 142 @Test testDisplayPreference_savesPreference()143 public void testDisplayPreference_savesPreference() throws Exception { 144 NotificationSoundPreference pref = mock(NotificationSoundPreference.class); 145 when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); 146 mController.displayPreference(mScreen); 147 148 mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent()); 149 verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any()); 150 } 151 152 @Test testUpdateState_disabledByAdmin()153 public void testUpdateState_disabledByAdmin() throws Exception { 154 NotificationChannel channel = mock(NotificationChannel.class); 155 when(channel.getId()).thenReturn("something"); 156 mController.onResume(new NotificationBackend.AppRow(), channel, null, mock( 157 RestrictedLockUtils.EnforcedAdmin.class)); 158 159 Preference pref = new NotificationSoundPreference(mContext, mock(AttributeSet.class)); 160 mController.updateState(pref); 161 162 assertFalse(pref.isEnabled()); 163 } 164 165 @Test testUpdateState_notConfigurable()166 public void testUpdateState_notConfigurable() throws Exception { 167 String lockedId = "locked"; 168 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 169 appRow.lockedChannelId = lockedId; 170 NotificationChannel channel = mock(NotificationChannel.class); 171 when(channel.getId()).thenReturn(lockedId); 172 mController.onResume(appRow, channel, null, null); 173 174 Preference pref = new NotificationSoundPreference(mContext, mock(AttributeSet.class)); 175 mController.updateState(pref); 176 177 assertFalse(pref.isEnabled()); 178 } 179 180 @Test testUpdateState_configurable()181 public void testUpdateState_configurable() throws Exception { 182 Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI; 183 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 184 NotificationChannel channel = mock(NotificationChannel.class); 185 when(channel.getId()).thenReturn("something"); 186 when(channel.getSound()).thenReturn(sound); 187 mController.onResume(appRow, channel, null, null); 188 189 NotificationSoundPreference pref = 190 new NotificationSoundPreference(mContext, mock(AttributeSet.class)); 191 mController.updateState(pref); 192 193 assertEquals(sound, pref.onRestoreRingtone()); 194 assertTrue(pref.isEnabled()); 195 } 196 197 @Test testOnPreferenceChange()198 public void testOnPreferenceChange() throws Exception { 199 Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI; 200 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow(); 201 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH); 202 channel.setSound(sound, Notification.AUDIO_ATTRIBUTES_DEFAULT); 203 mController.onResume(appRow, channel, null, null); 204 205 NotificationSoundPreference pref = 206 new NotificationSoundPreference(mContext, mock(AttributeSet.class)); 207 mController.updateState(pref); 208 209 mController.onPreferenceChange(pref, Uri.EMPTY); 210 assertEquals(Uri.EMPTY, channel.getSound()); 211 assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes()); 212 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any()); 213 } 214 215 @Test testOnPreferenceTreeClick_incorrectPref()216 public void testOnPreferenceTreeClick_incorrectPref() throws Exception { 217 NotificationSoundPreference pref = mock(NotificationSoundPreference.class); 218 mController.handlePreferenceTreeClick(pref); 219 220 verify(pref, never()).onPrepareRingtonePickerIntent(any()); 221 verify(mFragment, never()).startActivityForResult(any(), anyInt()); 222 } 223 224 @Test testOnPreferenceTreeClick_correctPref()225 public void testOnPreferenceTreeClick_correctPref() throws Exception { 226 NotificationSoundPreference pref = 227 spy(new NotificationSoundPreference(mContext, mock(AttributeSet.class))); 228 pref.setKey(mController.getPreferenceKey()); 229 mController.handlePreferenceTreeClick(pref); 230 231 verify(pref, times(1)).onPrepareRingtonePickerIntent(any()); 232 verify(mFragment, times(1)).startActivityForResult(any(), anyInt()); 233 } 234 235 @Test testOnActivityResult()236 public void testOnActivityResult() { 237 NotificationSoundPreference pref = mock(NotificationSoundPreference.class); 238 when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref); 239 mController.displayPreference(mScreen); 240 241 mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent("hi")); 242 verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any()); 243 verify(mImportanceListener, times(1)).onImportanceChanged(); 244 } 245 246 @Test testHasValidSound()247 public void testHasValidSound() { 248 NotificationChannel channel = 249 new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH); 250 assertTrue(SoundPreferenceController.hasValidSound(channel)); 251 252 channel.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT); 253 assertFalse(SoundPreferenceController.hasValidSound(channel)); 254 255 channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 256 assertFalse(SoundPreferenceController.hasValidSound(channel)); 257 } 258 } 259