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_noPrivateLockScreenNotificationsGlobally() {
213 Settings.Secure.putInt(mContext.getContentResolver(),
214 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
215 Settings.Secure.putInt(mContext.getContentResolver(),
216 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
218 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
219 NotificationChannel channel = mock(NotificationChannel.class);
220 mController.onResume(appRow, channel, null, null);
222 RestrictedListPreference pref = mock(RestrictedListPreference.class);
223 mController.updateState(pref);
225 ArgumentCaptor<CharSequence[]> argumentCaptor =
226 ArgumentCaptor.forClass(CharSequence[].class);
227 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
228 assertEquals(2, toStringList(argumentCaptor.getValue()).size());
229 assertFalse(toStringList(argumentCaptor.getValue())
230 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
234 public void testUpdateState_noGlobalRestriction() {
235 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
236 NotificationChannel channel = mock(NotificationChannel.class);
237 mController.onResume(appRow, channel, null, null);
239 RestrictedListPreference pref = mock(RestrictedListPreference.class);
240 mController.updateState(pref);
242 ArgumentCaptor<CharSequence[]> argumentCaptor =
243 ArgumentCaptor.forClass(CharSequence[].class);
244 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
245 List<String> values = toStringList(argumentCaptor.getValue());
246 assertEquals(3, values.size());
247 assertTrue(values.contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
248 assertTrue(values.contains(String.valueOf(VISIBILITY_PRIVATE)));
249 assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_SECRET)));
252 private static List<String> toStringList(CharSequence[] charSequences) {
253 List<String> result = new ArrayList<>();
254 for (CharSequence charSequence : charSequences) {
255 result.add(charSequence.toString());
261 public void testUpdateState_noChannelOverride() {
262 Settings.Secure.putInt(mContext.getContentResolver(),
263 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
265 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
266 NotificationChannel channel = mock(NotificationChannel.class);
267 when(channel.getLockscreenVisibility()).thenReturn(VISIBILITY_NO_OVERRIDE);
268 mController.onResume(appRow, channel, null, null);
270 RestrictedListPreference pref = mock(RestrictedListPreference.class);
271 mController.updateState(pref);
273 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
274 verify(pref, times(1)).setValue(argumentCaptor.capture());
276 assertEquals(String.valueOf(VISIBILITY_PRIVATE), argumentCaptor.getValue());
280 public void testUpdateState_channelOverride() {
281 Settings.Secure.putInt(mContext.getContentResolver(),
282 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
284 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
285 NotificationChannel channel = mock(NotificationChannel.class);
286 when(channel.getLockscreenVisibility()).thenReturn(Notification.VISIBILITY_SECRET);
287 mController.onResume(appRow, channel, null, null);
289 RestrictedListPreference pref = mock(RestrictedListPreference.class);
290 mController.updateState(pref);
292 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
293 verify(pref, times(1)).setValue(argumentCaptor.capture());
295 assertEquals(String.valueOf(Notification.VISIBILITY_SECRET), argumentCaptor.getValue());
299 public void testOnPreferenceChange_noOverride() {
300 Settings.Secure.putInt(mContext.getContentResolver(),
301 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
303 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
304 NotificationChannel channel = new NotificationChannel("", "", 4);
305 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
306 mController.onResume(appRow, channel, null, null);
308 RestrictedListPreference pref = mock(RestrictedListPreference.class);
309 mController.updateState(pref);
311 mController.onPreferenceChange(pref, String.valueOf(VISIBILITY_PRIVATE));
313 assertEquals(VISIBILITY_NO_OVERRIDE, channel.getLockscreenVisibility());
314 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
318 public void testOnPreferenceChange_override() {
319 Settings.Secure.putInt(mContext.getContentResolver(),
320 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
322 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
323 NotificationChannel channel = new NotificationChannel("", "", 4);
324 channel.setLockscreenVisibility(VISIBILITY_NO_OVERRIDE);
325 mController.onResume(appRow, channel, null, null);
327 RestrictedListPreference pref = mock(RestrictedListPreference.class);
328 mController.updateState(pref);
330 mController.onPreferenceChange(pref, String.valueOf(Notification.VISIBILITY_SECRET));
332 assertEquals(Notification.VISIBILITY_SECRET, channel.getLockscreenVisibility());
333 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());