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;
27 import static junit.framework.Assert.assertFalse;
28 import static junit.framework.Assert.assertTrue;
30 import static org.junit.Assert.assertEquals;
31 import static org.mockito.ArgumentMatchers.any;
32 import static org.mockito.ArgumentMatchers.anyInt;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.spy;
35 import static org.mockito.Mockito.times;
36 import static org.mockito.Mockito.verify;
37 import static org.mockito.Mockito.when;
39 import android.app.Notification;
40 import android.app.NotificationChannel;
41 import android.app.NotificationManager;
42 import android.app.admin.DevicePolicyManager;
43 import android.content.ComponentName;
44 import android.content.Context;
45 import android.content.pm.UserInfo;
46 import android.os.UserManager;
47 import android.provider.Settings;
48 import android.support.v7.preference.PreferenceScreen;
50 import com.android.internal.widget.LockPatternUtils;
51 import com.android.settings.RestrictedListPreference;
52 import com.android.settings.TestConfig;
53 import com.android.settings.testutils.SettingsRobolectricTestRunner;
54 import com.android.settings.testutils.shadow.ShadowRestrictionUtils;
55 import com.android.settingslib.RestrictedLockUtils;
57 import org.junit.Before;
58 import org.junit.Test;
59 import org.junit.runner.RunWith;
60 import org.mockito.Answers;
61 import org.mockito.ArgumentCaptor;
62 import org.mockito.Mock;
63 import org.mockito.MockitoAnnotations;
64 import org.robolectric.annotation.Config;
65 import org.robolectric.shadows.ShadowApplication;
67 import java.util.ArrayList;
68 import java.util.Arrays;
69 import java.util.List;
71 @RunWith(SettingsRobolectricTestRunner.class)
72 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, shadows = {
73 ShadowRestrictionUtils.class,
75 public class VisibilityPreferenceControllerTest {
77 private Context mContext;
79 private NotificationBackend mBackend;
81 private NotificationManager mNm;
83 private LockPatternUtils mLockUtils;
85 private UserManager mUm;
87 private DevicePolicyManager mDm;
88 @Mock(answer = Answers.RETURNS_DEEP_STUBS)
89 private PreferenceScreen mScreen;
91 private VisibilityPreferenceController mController;
95 MockitoAnnotations.initMocks(this);
96 ShadowApplication shadowApplication = ShadowApplication.getInstance();
97 shadowApplication.setSystemService(Context.NOTIFICATION_SERVICE, mNm);
98 shadowApplication.setSystemService(Context.USER_SERVICE, mUm);
99 shadowApplication.setSystemService(Context.DEVICE_POLICY_SERVICE, mDm);
100 mContext = shadowApplication.getApplicationContext();
101 mController = spy(new VisibilityPreferenceController(mContext, mLockUtils, mBackend));
103 // by default the lockscreen is secure
104 when(mLockUtils.isSecure(anyInt())).thenReturn(true);
105 // and notifications are visible in redacted form
106 Settings.Secure.putInt(mContext.getContentResolver(),
107 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
108 Settings.Secure.putInt(mContext.getContentResolver(),
109 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1);
110 // and not restricted
111 ShadowRestrictionUtils.setRestricted(false);
112 // with no managed profile
113 UserInfo userInfo = new UserInfo();
114 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
118 public void testNoCrashIfNoOnResume() {
119 mController.isAvailable();
120 mController.updateState(mock(RestrictedListPreference.class));
121 mController.onPreferenceChange(mock(RestrictedListPreference.class), true);
125 public void testIsAvailable_notSecure() {
126 when(mLockUtils.isSecure(anyInt())).thenReturn(false);
127 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
128 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
129 mController.onResume(appRow, channel, null, null);
130 assertFalse(mController.isAvailable());
134 public void testIsAvailable_notIfNotImportant() {
135 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
136 NotificationChannel channel = new NotificationChannel("", "", IMPORTANCE_MIN);
137 mController.onResume(appRow, channel, null, null);
138 assertFalse(mController.isAvailable());
142 public void testIsAvailable() {
143 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
144 NotificationChannel channel =
145 new NotificationChannel(DEFAULT_CHANNEL_ID, "", IMPORTANCE_DEFAULT);
146 mController.onResume(appRow, channel, null, null);
147 assertTrue(mController.isAvailable());
149 channel = new NotificationChannel("", "", IMPORTANCE_DEFAULT);
150 mController.onResume(appRow, channel, null, null);
151 assertTrue(mController.isAvailable());
155 public void testUpdateState_disabledByAdmin_disableSecure() {
156 ShadowRestrictionUtils.setRestricted(true);
157 UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
158 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
159 List<ComponentName> components = new ArrayList<>();
160 components.add(new ComponentName("", ""));
161 when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
162 when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
163 .thenReturn(KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
165 NotificationChannel channel = mock(NotificationChannel.class);
166 when(channel.getId()).thenReturn("something");
167 mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
168 RestrictedLockUtils.EnforcedAdmin.class));
170 RestrictedListPreference pref = mock(RestrictedListPreference.class);
171 mController.updateState(pref);
173 verify(pref, times(2)).addRestrictedItem(any());
177 public void testUpdateState_disabledByAdmin_disableUnredacted() {
178 ShadowRestrictionUtils.setRestricted(true);
179 UserInfo userInfo = new UserInfo(2, "user 2", UserInfo.FLAG_MANAGED_PROFILE);
180 when(mUm.getUserInfo(anyInt())).thenReturn(userInfo);
181 List<ComponentName> components = new ArrayList<>();
182 components.add(new ComponentName("", ""));
183 when(mDm.getActiveAdminsAsUser(anyInt())).thenReturn(components);
184 when(mDm.getKeyguardDisabledFeatures(any(), anyInt()))
185 .thenReturn(KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
187 NotificationChannel channel = mock(NotificationChannel.class);
188 when(channel.getId()).thenReturn("something");
189 mController.onResume(new NotificationBackend.AppRow(), channel, null, mock(
190 RestrictedLockUtils.EnforcedAdmin.class));
192 RestrictedListPreference pref = mock(RestrictedListPreference.class);
193 mController.updateState(pref);
195 verify(pref, times(1)).addRestrictedItem(any());
199 public void testUpdateState_noLockScreenNotificationsGlobally() {
200 Settings.Secure.putInt(mContext.getContentResolver(),
201 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0);
203 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
204 NotificationChannel channel = mock(NotificationChannel.class);
205 mController.onResume(appRow, channel, null, null);
207 RestrictedListPreference pref = mock(RestrictedListPreference.class);
208 mController.updateState(pref);
210 ArgumentCaptor<CharSequence[]> argumentCaptor =
211 ArgumentCaptor.forClass(CharSequence[].class);
212 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
213 assertFalse(toStringList(argumentCaptor.getValue())
214 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
215 assertFalse(toStringList(argumentCaptor.getValue())
216 .contains(String.valueOf(VISIBILITY_PRIVATE)));
220 public void testUpdateState_noPrivateLockScreenNotificationsGlobally() {
221 Settings.Secure.putInt(mContext.getContentResolver(),
222 Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 1);
223 Settings.Secure.putInt(mContext.getContentResolver(),
224 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
226 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
227 NotificationChannel channel = mock(NotificationChannel.class);
228 mController.onResume(appRow, channel, null, null);
230 RestrictedListPreference pref = mock(RestrictedListPreference.class);
231 mController.updateState(pref);
233 ArgumentCaptor<CharSequence[]> argumentCaptor =
234 ArgumentCaptor.forClass(CharSequence[].class);
235 verify(pref, times(1)).setEntryValues(argumentCaptor.capture());
236 assertEquals(2, toStringList(argumentCaptor.getValue()).size());
237 assertFalse(toStringList(argumentCaptor.getValue())
238 .contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
242 public void testUpdateState_noGlobalRestriction() {
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 List<String> values = toStringList(argumentCaptor.getValue());
254 assertEquals(3, values.size());
255 assertTrue(values.contains(String.valueOf(VISIBILITY_NO_OVERRIDE)));
256 assertTrue(values.contains(String.valueOf(VISIBILITY_PRIVATE)));
257 assertTrue(values.contains(String.valueOf(Notification.VISIBILITY_SECRET)));
260 private static List<String> toStringList(CharSequence[] charSequences) {
261 List<String> result = new ArrayList<>();
262 for (CharSequence charSequence : charSequences) {
263 result.add(charSequence.toString());
269 public void testUpdateState_noChannelOverride() {
270 Settings.Secure.putInt(mContext.getContentResolver(),
271 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
273 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
274 NotificationChannel channel = mock(NotificationChannel.class);
275 when(channel.getLockscreenVisibility()).thenReturn(VISIBILITY_NO_OVERRIDE);
276 mController.onResume(appRow, channel, null, null);
278 RestrictedListPreference pref = mock(RestrictedListPreference.class);
279 mController.updateState(pref);
281 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
282 verify(pref, times(1)).setValue(argumentCaptor.capture());
284 assertEquals(String.valueOf(VISIBILITY_PRIVATE), argumentCaptor.getValue());
288 public void testUpdateState_channelOverride() {
289 Settings.Secure.putInt(mContext.getContentResolver(),
290 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
292 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
293 NotificationChannel channel = mock(NotificationChannel.class);
294 when(channel.getLockscreenVisibility()).thenReturn(Notification.VISIBILITY_SECRET);
295 mController.onResume(appRow, channel, null, null);
297 RestrictedListPreference pref = mock(RestrictedListPreference.class);
298 mController.updateState(pref);
300 ArgumentCaptor<String> argumentCaptor = ArgumentCaptor.forClass(String.class);
301 verify(pref, times(1)).setValue(argumentCaptor.capture());
303 assertEquals(String.valueOf(Notification.VISIBILITY_SECRET), argumentCaptor.getValue());
307 public void testOnPreferenceChange_noOverride() {
308 Settings.Secure.putInt(mContext.getContentResolver(),
309 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
311 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
312 NotificationChannel channel = new NotificationChannel("", "", 4);
313 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
314 mController.onResume(appRow, channel, null, null);
316 RestrictedListPreference pref = mock(RestrictedListPreference.class);
317 mController.updateState(pref);
319 mController.onPreferenceChange(pref, String.valueOf(VISIBILITY_PRIVATE));
321 assertEquals(VISIBILITY_NO_OVERRIDE, channel.getLockscreenVisibility());
322 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());
326 public void testOnPreferenceChange_override() {
327 Settings.Secure.putInt(mContext.getContentResolver(),
328 Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 0);
330 NotificationBackend.AppRow appRow = new NotificationBackend.AppRow();
331 NotificationChannel channel = new NotificationChannel("", "", 4);
332 channel.setLockscreenVisibility(VISIBILITY_NO_OVERRIDE);
333 mController.onResume(appRow, channel, null, null);
335 RestrictedListPreference pref = mock(RestrictedListPreference.class);
336 mController.updateState(pref);
338 mController.onPreferenceChange(pref, String.valueOf(Notification.VISIBILITY_SECRET));
340 assertEquals(Notification.VISIBILITY_SECRET, channel.getLockscreenVisibility());
341 verify(mBackend, times(1)).updateChannel(any(), anyInt(), any());