2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.settings.notification;
19 import static android.app.Notification.VISIBILITY_PRIVATE;
20 import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID;
21 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
22 import static android.app.NotificationManager.IMPORTANCE_MIN;
23 import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
24 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS;
25 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
26 import static junit.framework.Assert.assertFalse;
27 import static junit.framework.Assert.assertTrue;
28 import static org.junit.Assert.assertEquals;
29 import static org.mockito.ArgumentMatchers.any;
30 import static org.mockito.ArgumentMatchers.anyInt;
31 import static org.mockito.Mockito.mock;
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;
37 import android.app.Notification;
38 import android.app.NotificationChannel;
39 import android.app.NotificationManager;
40 import android.app.admin.DevicePolicyManager;
41 import android.content.ComponentName;
42 import android.content.Context;
43 import android.content.pm.UserInfo;
44 import android.os.UserManager;
45 import android.provider.Settings;
47 import com.android.internal.widget.LockPatternUtils;
48 import com.android.settings.RestrictedListPreference;
49 import com.android.settings.testutils.SettingsRobolectricTestRunner;
50 import com.android.settings.testutils.shadow.ShadowRestrictionUtils;
51 import com.android.settingslib.RestrictedLockUtils;
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.ArgumentCaptor;
58 import org.mockito.Mock;
59 import org.mockito.MockitoAnnotations;
60 import org.robolectric.annotation.Config;
61 import org.robolectric.shadows.ShadowApplication;
63 import java.util.ArrayList;
64 import java.util.List;
66 @RunWith(SettingsRobolectricTestRunner.class)
67 @Config(shadows = ShadowRestrictionUtils.class)
68 public class VisibilityPreferenceControllerTest {
70 private Context mContext;
72 private NotificationBackend mBackend;
74 private NotificationManager mNm;
76 private LockPatternUtils mLockUtils;
78 private UserManager mUm;
80 private DevicePolicyManager mDm;
81 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
83 private VisibilityPreferenceController mController;
87 MockitoAnnotations.initMocks(this);
88 ShadowApplication shadowApplication = ShadowApplication.getInstance();
89 shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
90 shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
91 shadowApplication.setSystemService(Context.DEVICE_POLICY_SERVICE, mDm);
92 mContext = shadowApplication.getApplicationContext();
93 mController = spy(new VisibilityPreferenceController(mContext, mLockUtils, mBackend));
95 // by default the lockscreen is secure
96 when(mLockUtils.isSecure(anyInt())).thenReturn(true);
97 // and notifications are visible in redacted form
98 Settings.Secure.putInt(mContext.getContentResolver(),
99 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
100 Settings.Secure.putInt(mContext.getContentResolver(),
101 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
102 // and not restricted
103 ShadowRestrictionUtils.setRestricted(false);
104 // with no managed profile
105 UserInfo userInfo = new UserInfo();
106 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
110 public void testNoCrashIfNoOnResume() {
111 mController.isAvailable();
112 mController.updateState(mock(RestrictedListPreference.class));
113 mController.onPreferenceChange(mock(RestrictedListPreference.class), true);
117 public void testIsAvailable_notSecure() {
118 when(mLockUtils.isSecure(anyInt())).thenReturn(false);
119 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
120 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
121 mController.onResume(appRow, channel, null, null);
122 assertFalse(mController.isAvailable());
126 public void testIsAvailable_notIfNotImportant() {
127 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
128 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
129 mController.onResume(appRow, channel, null, null);
130 assertFalse(mController.isAvailable());
134 public void testIsAvailable() {
135 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
136 NotificationChannel channel =
137 new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
138 mController.onResume(appRow, channel, null, null);
139 assertTrue(mController.isAvailable());
141 channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
142 mController.onResume(appRow, channel, null, null);
143 assertTrue(mController.isAvailable());
147 public void testUpdateState_disabledByAdmin_disableSecure() {
148 ShadowRestrictionUtils.setRestricted(true);
149 UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
150 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
151 List<ComponentName> components = new ArrayList<>();
152 components.add(new ComponentName("", ""));
153 when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
154 when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
155 .thenReturn(KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
157 NotificationChannel channel = mock(NotificationChannel.class);
158 when(channel.getId()).thenReturn("something");
159 mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
160 RestrictedLockUtils.EnforcedAdmin.class));
162 RestrictedListPreference pref = mock(RestrictedListPreference.class);
163 mController.updateState(pref);
165 verify(pref, times(2)).addRestrictedItem(any());
169 public void testUpdateState_disabledByAdmin_disableUnredacted() {
170 ShadowRestrictionUtils.setRestricted(true);
171 UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
172 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
173 List<ComponentName> components = new ArrayList<>();
174 components.add(new ComponentName("", ""));
175 when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
176 when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
177 .thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
179 NotificationChannel channel = mock(NotificationChannel.class);
180 when(channel.getId()).thenReturn("something");
181 mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
182 RestrictedLockUtils.EnforcedAdmin.class));
184 RestrictedListPreference pref = mock(RestrictedListPreference.class);
185 mController.updateState(pref);
187 verify(pref, times(1)).addRestrictedItem(any());
191 public void testUpdateState_noLockScreenNotificationsGlobally() {
192 Settings.Secure.putInt(mContext.getContentResolver(),
193 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
195 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
196 NotificationChannel channel = mock(NotificationChannel.class);
197 mController.onResume(appRow, channel, null, null);
199 RestrictedListPreference pref = mock(RestrictedListPreference.class);
200 mController.updateState(pref);
202 ArgumentCaptor<CharSequence[]> argumentCaptor =
203 ArgumentCaptor.forClass(CharSequence[].class);
204 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
205 assertFalse(toStringList(argumentCaptor.getValue())
206 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
207 assertFalse(toStringList(argumentCaptor.getValue())
208 .contains(String.valueOf(VISIBILITY_PRIVATE)));
212 public void testUpdateState_noLockScreenNotificationsGloballyInProfile() {
213 final int primaryUserId = 2;
214 final UserInfo primaryUserInfo = new UserInfo(primaryUserId, "user 2", 0);
215 when(mUm.getProfileParent(anyInt())).thenReturn(primaryUserInfo);
217 Settings.Secure.putIntForUser(mContext.getContentResolver(),
218 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, primaryUserId);
220 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
221 NotificationChannel channel = mock(NotificationChannel.class);
222 mController.onResume(appRow, channel, null, null);
224 RestrictedListPreference pref = mock(RestrictedListPreference.class);
225 mController.updateState(pref);
227 ArgumentCaptor<CharSequence[]> argumentCaptor =
228 ArgumentCaptor.forClass(CharSequence[].class);
229 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
230 assertFalse(toStringList(argumentCaptor.getValue())
231 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
232 assertFalse(toStringList(argumentCaptor.getValue())
233 .contains(String.valueOf(VISIBILITY_PRIVATE)));
237 public void testUpdateState_noPrivateLockScreenNotificationsGlobally() {
238 Settings.Secure.putInt(mContext.getContentResolver(),
239 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
240 Settings.Secure.putInt(mContext.getContentResolver(),
241 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
243 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
244 NotificationChannel channel = mock(NotificationChannel.class);
245 mController.onResume(appRow, channel, null, null);
247 RestrictedListPreference pref = mock(RestrictedListPreference.class);
248 mController.updateState(pref);
250 ArgumentCaptor<CharSequence[]> argumentCaptor =
251 ArgumentCaptor.forClass(CharSequence[].class);
252 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
253 assertEquals(2, toStringList(argumentCaptor.getValue()).size());
254 assertFalse(toStringList(argumentCaptor.getValue())
255 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
259 public void testUpdateState_noGlobalRestriction() {
260 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
261 NotificationChannel channel = mock(NotificationChannel.class);
262 mController.onResume(appRow, channel, null, null);
264 RestrictedListPreference pref = mock(RestrictedListPreference.class);
265 mController.updateState(pref);
267 ArgumentCaptor<CharSequence[]> argumentCaptor =
268 ArgumentCaptor.forClass(CharSequence[].class);
269 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
270 List<String> values = toStringList(argumentCaptor.getValue());
271 assertEquals(3, values.size());
272 assertTrue(values.contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
273 assertTrue(values.contains(String.valueOf(VISIBILITY_PRIVATE)));
274 assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_SECRET)));
277 private static List<String> toStringList(CharSequence[] charSequences) {
278 List<String> result = new ArrayList<>();
279 for (CharSequence charSequence : charSequences) {
280 result.add(charSequence.toString());
286 public void testUpdateState_noChannelOverride() {
287 Settings.Secure.putInt(mContext.getContentResolver(),
288 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
290 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
291 NotificationChannel channel = mock(NotificationChannel.class);
292 when(channel.getLockscreenVisibility()).thenReturn(VISIBILITY_NO_OVERRIDE);
293 mController.onResume(appRow, channel, null, null);
295 RestrictedListPreference pref = mock(RestrictedListPreference.class);
296 mController.updateState(pref);
298 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
299 verify(pref, times(1)).setValue(argumentCaptor.capture());
301 assertEquals(String.valueOf(VISIBILITY_PRIVATE), argumentCaptor.getValue());
305 public void testUpdateState_channelOverride() {
306 Settings.Secure.putInt(mContext.getContentResolver(),
307 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
309 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
310 NotificationChannel channel = mock(NotificationChannel.class);
311 when(channel.getLockscreenVisibility()).thenReturn(Notification.VISIBILITY_SECRET);
312 mController.onResume(appRow, channel, null, null);
314 RestrictedListPreference pref = mock(RestrictedListPreference.class);
315 mController.updateState(pref);
317 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
318 verify(pref, times(1)).setValue(argumentCaptor.capture());
320 assertEquals(String.valueOf(Notification.VISIBILITY_SECRET), argumentCaptor.getValue());
324 public void testOnPreferenceChange_noOverride() {
325 Settings.Secure.putInt(mContext.getContentResolver(),
326 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
328 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
329 NotificationChannel channel = new NotificationChannel("", "", 4);
330 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
331 mController.onResume(appRow, channel, null, null);
333 RestrictedListPreference pref = mock(RestrictedListPreference.class);
334 mController.updateState(pref);
336 mController.onPreferenceChange(pref, String.valueOf(VISIBILITY_PRIVATE));
338 assertEquals(VISIBILITY_NO_OVERRIDE, channel.getLockscreenVisibility());
339 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
343 public void testOnPreferenceChange_override() {
344 Settings.Secure.putInt(mContext.getContentResolver(),
345 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
347 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
348 NotificationChannel channel = new NotificationChannel("", "", 4);
349 channel.setLockscreenVisibility(VISIBILITY_NO_OVERRIDE);
350 mController.onResume(appRow, channel, null, null);
352 RestrictedListPreference pref = mock(RestrictedListPreference.class);
353 mController.updateState(pref);
355 mController.onPreferenceChange(pref, String.valueOf(Notification.VISIBILITY_SECRET));
357 assertEquals(Notification.VISIBILITY_SECRET, channel.getLockscreenVisibility());
358 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());