• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
24 import static org.junit.Assert.assertFalse;
25 import static org.junit.Assert.assertTrue;
26 
27 import static org.junit.Assert.assertEquals;
28 import static org.mockito.ArgumentMatchers.any;
29 import static org.mockito.ArgumentMatchers.anyInt;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.never;
32 import static org.mockito.Mockito.spy;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 import static org.mockito.Mockito.when;
36 
37 import android.app.Notification;
38 import android.app.NotificationChannel;
39 import android.app.NotificationManager;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.media.AudioAttributes;
43 import android.media.RingtoneManager;
44 import android.net.Uri;
45 import android.os.UserManager;
46 import android.provider.Settings;
47 import android.util.AttributeSet;
48 
49 import androidx.preference.Preference;
50 import androidx.preference.PreferenceScreen;
51 
52 import com.android.settings.SettingsPreferenceFragment;
53 import com.android.settingslib.RestrictedLockUtils;
54 
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.junit.runner.RunWith;
58 import org.mockito.Answers;
59 import org.mockito.ArgumentCaptor;
60 import org.mockito.Mock;
61 import org.mockito.MockitoAnnotations;
62 import org.robolectric.Robolectric;
63 import org.robolectric.RobolectricTestRunner;
64 import org.robolectric.RuntimeEnvironment;
65 import org.robolectric.shadows.ShadowApplication;
66 
67 @RunWith(RobolectricTestRunner.class)
68 public class SoundPreferenceControllerTest {
69 
70     private Context mContext;
71     @Mock
72     private NotificationBackend mBackend;
73     @Mock
74     private NotificationManager mNm;
75     @Mock
76     private UserManager mUm;
77     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
78     private PreferenceScreen mScreen;
79     @Mock
80     private SettingsPreferenceFragment mFragment;
81     @Mock
82     private NotificationSettingsBase.ImportanceListener mImportanceListener;
83 
84     private SoundPreferenceController mController;
85 
86     @Before
setUp()87     public void setUp() {
88         MockitoAnnotations.initMocks(this);
89         ShadowApplication shadowApplication = ShadowApplication.getInstance();
90         shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
91         shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
92         mContext = RuntimeEnvironment.application;
93         mController = spy(new SoundPreferenceController(
94                 mContext, mFragment, mImportanceListener, mBackend));
95     }
96 
97     @Test
testNoCrashIfNoOnResume()98     public void testNoCrashIfNoOnResume() {
99         mController.isAvailable();
100         mController.updateState(mock(NotificationSoundPreference.class));
101         mController.onPreferenceChange(mock(NotificationSoundPreference.class), Uri.EMPTY);
102         mController.handlePreferenceTreeClick(mock(NotificationSoundPreference.class));
103         mController.onActivityResult(1, 1, null);
104         SoundPreferenceController.hasValidSound(null);
105     }
106 
107     @Test
testIsAvailable_notIfChannelNull()108     public void testIsAvailable_notIfChannelNull() {
109         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
110         mController.onResume(appRow, null, null, null);
111         assertFalse(mController.isAvailable());
112     }
113 
114     @Test
testIsAvailable_notIfNotImportant()115     public void testIsAvailable_notIfNotImportant() {
116         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
117         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_LOW);
118         mController.onResume(appRow, channel, null, null);
119         assertFalse(mController.isAvailable());
120     }
121 
122     @Test
testIsAvailable_notIfDefaultChannel()123     public void testIsAvailable_notIfDefaultChannel() {
124         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
125         NotificationChannel channel =
126                 new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
127         mController.onResume(appRow, channel, null, null);
128         assertFalse(mController.isAvailable());
129     }
130 
131     @Test
testIsAvailable()132     public void testIsAvailable() {
133         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
134         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
135         mController.onResume(appRow, channel, null, null);
136         assertTrue(mController.isAvailable());
137     }
138 
139     @Test
testDisplayPreference_savesPreference()140     public void testDisplayPreference_savesPreference() {
141         NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
142         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
143         mController.displayPreference(mScreen);
144 
145         mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent());
146         verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any());
147     }
148 
149     @Test
testUpdateState_disabledByAdmin()150     public void testUpdateState_disabledByAdmin() {
151         NotificationChannel channel = mock(NotificationChannel.class);
152         when(channel.getId()).thenReturn("something");
153         mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
154                 RestrictedLockUtils.EnforcedAdmin.class));
155 
156         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
157         Preference pref = new NotificationSoundPreference(mContext, attributeSet);
158         mController.updateState(pref);
159 
160         assertFalse(pref.isEnabled());
161     }
162 
163     @Test
testUpdateState_notBlockable()164     public void testUpdateState_notBlockable() {
165         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
166         NotificationChannel channel = mock(NotificationChannel.class);
167         when(channel.isImportanceLockedByOEM()).thenReturn(true);
168         mController.onResume(appRow, channel, null, null);
169 
170         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
171         Preference pref = new NotificationSoundPreference(mContext, attributeSet);
172         mController.updateState(pref);
173 
174         assertTrue(pref.isEnabled());
175     }
176 
177     @Test
testUpdateState_configurable()178     public void testUpdateState_configurable() {
179         Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI;
180         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
181         NotificationChannel channel = mock(NotificationChannel.class);
182         when(channel.getId()).thenReturn("something");
183         when(channel.getSound()).thenReturn(sound);
184         mController.onResume(appRow, channel, null, null);
185 
186         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
187         NotificationSoundPreference pref = new NotificationSoundPreference(mContext, attributeSet);
188         mController.updateState(pref);
189 
190         assertEquals(sound, pref.onRestoreRingtone());
191         assertTrue(pref.isEnabled());
192     }
193 
194     @Test
testOnPreferenceChange()195     public void testOnPreferenceChange() {
196         Uri sound = Settings.System.DEFAULT_ALARM_ALERT_URI;
197         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
198         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
199         channel.setSound(sound, Notification.AUDIO_ATTRIBUTES_DEFAULT);
200         mController.onResume(appRow, channel, null, null);
201 
202         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
203         NotificationSoundPreference pref =
204                 new NotificationSoundPreference(mContext, attributeSet);
205         mController.updateState(pref);
206 
207         mController.onPreferenceChange(pref, Uri.EMPTY);
208         assertEquals(Uri.EMPTY, channel.getSound());
209         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, channel.getAudioAttributes());
210         verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
211     }
212 
213     @Test
testOnPreferenceTreeClick_incorrectPref()214     public void testOnPreferenceTreeClick_incorrectPref() {
215         NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
216         mController.handlePreferenceTreeClick(pref);
217 
218         verify(pref, never()).onPrepareRingtonePickerIntent(any());
219         verify(mFragment, never()).startActivityForResult(any(), anyInt());
220     }
221 
222     @Test
testOnPreferenceTreeClick_correctPref()223     public void testOnPreferenceTreeClick_correctPref() {
224         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
225         NotificationSoundPreference pref =
226                 spy(new NotificationSoundPreference(mContext, attributeSet));
227         pref.setKey(mController.getPreferenceKey());
228         mController.handlePreferenceTreeClick(pref);
229 
230         verify(pref, times(1)).onPrepareRingtonePickerIntent(any());
231         verify(mFragment, times(1)).startActivityForResult(any(), anyInt());
232     }
233 
234     @Test
testOnPreferenceTreeClick_alarmSound()235     public void testOnPreferenceTreeClick_alarmSound() {
236         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
237         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
238         channel.setSound(null, new AudioAttributes.Builder().setUsage(
239                 AudioAttributes.USAGE_ALARM).build());
240         mController.onResume(appRow, channel, null, null);
241 
242         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
243         NotificationSoundPreference pref =
244                 spy(new NotificationSoundPreference(mContext, attributeSet));
245         pref.setKey(mController.getPreferenceKey());
246         mController.handlePreferenceTreeClick(pref);
247 
248         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
249         verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
250         assertEquals(RingtoneManager.TYPE_ALARM,
251                 intentArgumentCaptor.getValue().getIntExtra(
252                         RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
253     }
254 
255     @Test
testOnPreferenceTreeClick_ringtoneSound()256     public void testOnPreferenceTreeClick_ringtoneSound() {
257         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
258         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
259         channel.setSound(null, new AudioAttributes.Builder().setUsage(
260                 AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build());
261         mController.onResume(appRow, channel, null, null);
262 
263         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
264         NotificationSoundPreference pref =
265                 spy(new NotificationSoundPreference(mContext, attributeSet));
266         pref.setKey(mController.getPreferenceKey());
267         mController.handlePreferenceTreeClick(pref);
268 
269         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
270         verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
271         assertEquals(RingtoneManager.TYPE_RINGTONE,
272                 intentArgumentCaptor.getValue().getIntExtra(
273                         RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
274     }
275 
276     @Test
testOnPreferenceTreeClick_otherSound()277     public void testOnPreferenceTreeClick_otherSound() {
278         NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
279         NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_HIGH);
280         channel.setSound(null, new AudioAttributes.Builder().setUsage(
281                 AudioAttributes.USAGE_UNKNOWN).build());
282         mController.onResume(appRow, channel, null, null);
283 
284         AttributeSet attributeSet = Robolectric.buildAttributeSet().build();
285         NotificationSoundPreference pref =
286                 spy(new NotificationSoundPreference(mContext, attributeSet));
287         pref.setKey(mController.getPreferenceKey());
288         mController.handlePreferenceTreeClick(pref);
289 
290         ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
291         verify(pref, times(1)).onPrepareRingtonePickerIntent(intentArgumentCaptor.capture());
292         assertEquals(RingtoneManager.TYPE_NOTIFICATION,
293                 intentArgumentCaptor.getValue().getIntExtra(
294                         RingtoneManager.EXTRA_RINGTONE_TYPE, 0));
295     }
296 
297     @Test
testOnActivityResult()298     public void testOnActivityResult() {
299         NotificationSoundPreference pref = mock(NotificationSoundPreference.class);
300         when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(pref);
301         mController.displayPreference(mScreen);
302 
303         mController.onActivityResult(SoundPreferenceController.CODE, 1, new Intent("hi"));
304         verify(pref, times(1)).onActivityResult(anyInt(), anyInt(), any());
305         verify(mImportanceListener, times(1)).onImportanceChanged();
306     }
307 
308     @Test
testHasValidSound()309     public void testHasValidSound() {
310         NotificationChannel channel =
311                 new NotificationChannel(DEFAULT_CHANNEL_ID, "a", IMPORTANCE_HIGH);
312         assertTrue(SoundPreferenceController.hasValidSound(channel));
313 
314         channel.setSound(Uri.EMPTY, Notification.AUDIO_ATTRIBUTES_DEFAULT);
315         assertFalse(SoundPreferenceController.hasValidSound(channel));
316 
317         channel.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT);
318         assertFalse(SoundPreferenceController.hasValidSound(channel));
319     }
320 }
321