blob: 2fe51d35c490f539168fa34a14b86638aa2ea06d [file] [log] [blame]
Bartosz Fabianowski5f045002016-12-01 10:36:18 +01001/*
2 * Copyright (C) 2016 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
17package com.android.systemui.statusbar;
18
Lucas Dupinff6628d2018-10-15 10:12:37 -070019import static com.google.common.truth.Truth.assertThat;
20
Adrian Roosc1b50322017-02-27 21:07:58 +010021import static org.junit.Assert.assertFalse;
22import static org.junit.Assert.assertTrue;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070023import static org.mockito.ArgumentMatchers.any;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070024import static org.mockito.ArgumentMatchers.anyInt;
25import static org.mockito.ArgumentMatchers.eq;
Jason Monk3cfedd72016-12-09 09:31:37 -050026import static org.mockito.Mockito.mock;
27import static org.mockito.Mockito.reset;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070028import static org.mockito.Mockito.times;
Jason Monk3cfedd72016-12-09 09:31:37 -050029import static org.mockito.Mockito.verify;
30import static org.mockito.Mockito.verifyNoMoreInteractions;
31import static org.mockito.Mockito.when;
32
Adrian Roosc1b50322017-02-27 21:07:58 +010033import android.app.Instrumentation;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010034import android.app.admin.DevicePolicyManager;
35import android.app.trust.TrustManager;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010036import android.content.Context;
Lucas Dupinff6628d2018-10-15 10:12:37 -070037import android.graphics.Color;
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -080038import android.hardware.biometrics.BiometricSourceType;
39import android.hardware.face.FaceManager;
Jason Monk3cfedd72016-12-09 09:31:37 -050040import android.hardware.fingerprint.FingerprintManager;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010041import android.os.Looper;
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -080042import android.os.UserManager;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010043import android.view.View;
44import android.view.ViewGroup;
45
Brett Chabot84151d92019-02-27 15:37:59 -080046import androidx.test.InstrumentationRegistry;
47import androidx.test.filters.SmallTest;
48import androidx.test.runner.AndroidJUnit4;
49
Lucas Dupin2e838ac2019-04-17 16:50:58 -070050import com.android.internal.widget.LockPatternUtils;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070051import com.android.keyguard.KeyguardUpdateMonitor;
Adrian Roosaf45b602017-03-14 13:10:25 -070052import com.android.keyguard.KeyguardUpdateMonitorCallback;
Jerry Chang4bbf1592019-11-15 06:52:54 +080053import com.android.settingslib.Utils;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010054import com.android.systemui.R;
55import com.android.systemui.SysuiTestCase;
Jerry Chang4bbf1592019-11-15 06:52:54 +080056import com.android.systemui.dock.DockManager;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070057import com.android.systemui.plugins.statusbar.StatusBarStateController;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010058import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070059import com.android.systemui.statusbar.phone.LockIcon;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070060import com.android.systemui.statusbar.phone.ShadeController;
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -080061import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070062import com.android.systemui.statusbar.phone.UnlockMethodCache;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070063import com.android.systemui.statusbar.policy.AccessibilityController;
Adrian Roosc1b50322017-02-27 21:07:58 +010064import com.android.systemui.util.wakelock.WakeLockFake;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010065
66import org.junit.Before;
67import org.junit.Test;
68import org.junit.runner.RunWith;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070069import org.mockito.ArgumentCaptor;
Jerry Chang4bbf1592019-11-15 06:52:54 +080070import org.mockito.Captor;
Lucas Dupinff6628d2018-10-15 10:12:37 -070071import org.mockito.Mock;
72import org.mockito.MockitoAnnotations;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010073
74@SmallTest
75@RunWith(AndroidJUnit4.class)
76public class KeyguardIndicationControllerTest extends SysuiTestCase {
77
78 private final String ORGANIZATION_NAME = "organization";
Bartosz Fabianowski5f045002016-12-01 10:36:18 +010079
Jason Monk3cfedd72016-12-09 09:31:37 -050080 private String mDisclosureWithOrganization;
81
Lucas Dupinff6628d2018-10-15 10:12:37 -070082 @Mock
83 private DevicePolicyManager mDevicePolicyManager;
84 @Mock
85 private ViewGroup mIndicationArea;
86 @Mock
87 private KeyguardIndicationTextView mDisclosure;
Lucas Dupin2e838ac2019-04-17 16:50:58 -070088 @Mock
89 private LockIcon mLockIcon;
90 @Mock
91 private LockPatternUtils mLockPatternUtils;
Lucas Dupin0df60fe2019-04-23 10:19:27 -070092 @Mock
93 private ShadeController mShadeController;
94 @Mock
95 private AccessibilityController mAccessibilityController;
Lucas Dupin8e2fd012019-04-25 16:40:54 -070096 @Mock
97 private UnlockMethodCache mUnlockMethodCache;
98 @Mock
99 private StatusBarStateController mStatusBarStateController;
100 @Mock
101 private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800102 @Mock
103 private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
104 @Mock
105 private UserManager mUserManager;
Jerry Chang4bbf1592019-11-15 06:52:54 +0800106 @Mock
107 private DockManager mDockManager;
108 @Captor
109 private ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener;
Lucas Dupinff6628d2018-10-15 10:12:37 -0700110 private KeyguardIndicationTextView mTextView;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100111
112 private KeyguardIndicationController mController;
Adrian Roosc1b50322017-02-27 21:07:58 +0100113 private WakeLockFake mWakeLock;
114 private Instrumentation mInstrumentation;
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100115
116 @Before
117 public void setUp() throws Exception {
Lucas Dupinff6628d2018-10-15 10:12:37 -0700118 MockitoAnnotations.initMocks(this);
Adrian Roosc1b50322017-02-27 21:07:58 +0100119 mInstrumentation = InstrumentationRegistry.getInstrumentation();
Lucas Dupinff6628d2018-10-15 10:12:37 -0700120 mTextView = new KeyguardIndicationTextView(mContext);
Adrian Roosc1b50322017-02-27 21:07:58 +0100121
Jason Monk3cfedd72016-12-09 09:31:37 -0500122 mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800123 mContext.addMockSystemService(UserManager.class, mUserManager);
Jason Monk3cfedd72016-12-09 09:31:37 -0500124 mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class));
125 mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class));
126 mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name,
127 ORGANIZATION_NAME);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100128
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800129 when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed()).thenReturn(true);
130 when(mKeyguardUpdateMonitor.isScreenOn()).thenReturn(true);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100131 when(mIndicationArea.findViewById(R.id.keyguard_indication_enterprise_disclosure))
132 .thenReturn(mDisclosure);
Lucas Dupinff6628d2018-10-15 10:12:37 -0700133 when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView);
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800134 when(mUserManager.isUserUnlocked(anyInt())).thenReturn(true);
Adrian Roosc1b50322017-02-27 21:07:58 +0100135
136 mWakeLock = new WakeLockFake();
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100137 }
138
139 private void createController() {
140 if (Looper.myLooper() == null) {
141 Looper.prepare();
142 }
Lucas Dupin2e838ac2019-04-17 16:50:58 -0700143 mController = new KeyguardIndicationController(mContext, mIndicationArea, mLockIcon,
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700144 mLockPatternUtils, mWakeLock, mShadeController, mAccessibilityController,
Jerry Chang4bbf1592019-11-15 06:52:54 +0800145 mUnlockMethodCache, mStatusBarStateController, mKeyguardUpdateMonitor,
146 mDockManager);
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800147 mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100148 }
149
150 @Test
151 public void unmanaged() {
152 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
153 createController();
154
155 verify(mDisclosure).setVisibility(View.GONE);
156 verifyNoMoreInteractions(mDisclosure);
157 }
158
159 @Test
160 public void managedNoOwnerName() {
161 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
162 when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
163 createController();
164
165 verify(mDisclosure).setVisibility(View.VISIBLE);
166 verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
167 verifyNoMoreInteractions(mDisclosure);
168 }
169
170 @Test
171 public void managedOwnerName() {
172 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
173 when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
174 createController();
175
176 verify(mDisclosure).setVisibility(View.VISIBLE);
Jason Monk3cfedd72016-12-09 09:31:37 -0500177 verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100178 verifyNoMoreInteractions(mDisclosure);
179 }
180
181 @Test
182 public void updateOnTheFly() {
183 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
184 createController();
185
Adrian Roosaf45b602017-03-14 13:10:25 -0700186 final KeyguardUpdateMonitorCallback monitor = mController.getKeyguardCallback();
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100187 reset(mDisclosure);
188
189 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
190 when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(null);
191 monitor.onKeyguardVisibilityChanged(true);
192
193 verify(mDisclosure).setVisibility(View.VISIBLE);
194 verify(mDisclosure).switchIndication(R.string.do_disclosure_generic);
195 verifyNoMoreInteractions(mDisclosure);
196 reset(mDisclosure);
197
198 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(true);
199 when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn(ORGANIZATION_NAME);
200 monitor.onKeyguardVisibilityChanged(false);
201 monitor.onKeyguardVisibilityChanged(true);
202
203 verify(mDisclosure).setVisibility(View.VISIBLE);
Jason Monk3cfedd72016-12-09 09:31:37 -0500204 verify(mDisclosure).switchIndication(mDisclosureWithOrganization);
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100205 verifyNoMoreInteractions(mDisclosure);
206 reset(mDisclosure);
207
208 when(mDevicePolicyManager.isDeviceManaged()).thenReturn(false);
209 monitor.onKeyguardVisibilityChanged(false);
210 monitor.onKeyguardVisibilityChanged(true);
211
212 verify(mDisclosure).setVisibility(View.GONE);
213 verifyNoMoreInteractions(mDisclosure);
214 }
Adrian Roosc1b50322017-02-27 21:07:58 +0100215
216 @Test
Jerry Chang4bbf1592019-11-15 06:52:54 +0800217 public void createController_addsAlignmentListener() {
218 createController();
219
220 verify(mDockManager).addAlignmentStateListener(
221 any(DockManager.AlignmentStateListener.class));
222 }
223
224 @Test
225 public void onAlignmentStateChanged_showsSlowChargingIndication() {
226 createController();
227 verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
228 mController.setVisible(true);
229
230 mAlignmentListener.getValue().onAlignmentStateChanged(
231 DockManager.ALIGN_STATE_POOR);
232
233 assertThat(mTextView.getText()).isEqualTo(
234 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
235 assertThat(mTextView.getCurrentTextColor()).isEqualTo(
236 Utils.getColorError(mContext).getDefaultColor());
237 }
238
239 @Test
240 public void onAlignmentStateChanged_showsNotChargingIndication() {
241 createController();
242 verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
243 mController.setVisible(true);
244
245 mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
246
247 assertThat(mTextView.getText()).isEqualTo(
248 mContext.getResources().getString(R.string.dock_alignment_not_charging));
249 assertThat(mTextView.getCurrentTextColor()).isEqualTo(
250 Utils.getColorError(mContext).getDefaultColor());
251 }
252
253 @Test
254 public void onAlignmentStateChanged_whileDozing_showsSlowChargingIndication() {
255 createController();
256 verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
257 mController.setVisible(true);
258 mController.setDozing(true);
259
260 mAlignmentListener.getValue().onAlignmentStateChanged(
261 DockManager.ALIGN_STATE_POOR);
262
263 assertThat(mTextView.getText()).isEqualTo(
264 mContext.getResources().getString(R.string.dock_alignment_slow_charging));
265 assertThat(mTextView.getCurrentTextColor()).isEqualTo(
266 Utils.getColorError(mContext).getDefaultColor());
267 }
268
269 @Test
270 public void onAlignmentStateChanged_whileDozing_showsNotChargingIndication() {
271 createController();
272 verify(mDockManager).addAlignmentStateListener(mAlignmentListener.capture());
273 mController.setVisible(true);
274 mController.setDozing(true);
275
276 mAlignmentListener.getValue().onAlignmentStateChanged(DockManager.ALIGN_STATE_TERRIBLE);
277
278 assertThat(mTextView.getText()).isEqualTo(
279 mContext.getResources().getString(R.string.dock_alignment_not_charging));
280 assertThat(mTextView.getCurrentTextColor()).isEqualTo(
281 Utils.getColorError(mContext).getDefaultColor());
282 }
283
284 @Test
Adrian Roosc1b50322017-02-27 21:07:58 +0100285 public void transientIndication_holdsWakeLock_whenDozing() {
286 createController();
287
288 mController.setDozing(true);
289 mController.showTransientIndication("Test");
290
291 assertTrue(mWakeLock.isHeld());
292 }
293
294 @Test
295 public void transientIndication_releasesWakeLock_afterHiding() {
296 createController();
297
298 mController.setDozing(true);
299 mController.showTransientIndication("Test");
300 mController.hideTransientIndication();
301
302 assertFalse(mWakeLock.isHeld());
303 }
304
305 @Test
306 public void transientIndication_releasesWakeLock_afterHidingDelayed() throws Throwable {
307 mInstrumentation.runOnMainSync(() -> {
308 createController();
309
310 mController.setDozing(true);
311 mController.showTransientIndication("Test");
312 mController.hideTransientIndicationDelayed(0);
313 });
314 mInstrumentation.waitForIdleSync();
315
Adrian Roosaf45b602017-03-14 13:10:25 -0700316 Boolean[] held = new Boolean[1];
Adrian Roosc1b50322017-02-27 21:07:58 +0100317 mInstrumentation.runOnMainSync(() -> {
318 held[0] = mWakeLock.isHeld();
Adrian Roosc1b50322017-02-27 21:07:58 +0100319 });
Adrian Roosaf45b602017-03-14 13:10:25 -0700320 assertFalse("WakeLock expected: RELEASED, was: HELD", held[0]);
Adrian Roosc1b50322017-02-27 21:07:58 +0100321 }
Lucas Dupinff6628d2018-10-15 10:12:37 -0700322
323 @Test
324 public void transientIndication_visibleWhenDozing() {
325 createController();
326
327 mController.setVisible(true);
328 mController.showTransientIndication("Test");
329 mController.setDozing(true);
330
331 assertThat(mTextView.getText()).isEqualTo("Test");
332 assertThat(mTextView.getCurrentTextColor()).isEqualTo(Color.WHITE);
333 assertThat(mTextView.getAlpha()).isEqualTo(1f);
334 }
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700335
336 @Test
Lucas Dupinb54d7e2a2019-11-04 16:01:51 -0800337 public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromHelp() {
338 createController();
339 String message = "A message";
340
341 mController.setVisible(true);
342 mController.getKeyguardCallback().onBiometricHelp(
343 KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED, message,
344 BiometricSourceType.FACE);
345 assertThat(mTextView.getText()).isEqualTo(message);
346 mController.setDozing(true);
347
348 assertThat(mTextView.getText()).isNotEqualTo(message);
349 }
350
351 @Test
352 public void transientIndication_visibleWhenDozing_unlessSwipeUp_fromError() {
353 createController();
354 String message = mContext.getString(R.string.keyguard_unlock);
355
356 mController.setVisible(true);
357 mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
358 "A message", BiometricSourceType.FACE);
359
360 assertThat(mTextView.getText()).isEqualTo(message);
361 mController.setDozing(true);
362
363 assertThat(mTextView.getText()).isNotEqualTo(message);
364 }
365
366 @Test
367 public void transientIndication_swipeUpToRetry() {
368 createController();
369 String message = mContext.getString(R.string.keyguard_retry);
370 when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(true);
371
372 mController.setVisible(true);
373 mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
374 "A message", BiometricSourceType.FACE);
375
376 verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
377 }
378
379 @Test
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700380 public void lockIcon_click() {
381 createController();
382
383 ArgumentCaptor<View.OnLongClickListener> longClickCaptor = ArgumentCaptor.forClass(
384 View.OnLongClickListener.class);
385 ArgumentCaptor<View.OnClickListener> clickCaptor = ArgumentCaptor.forClass(
386 View.OnClickListener.class);
387 verify(mLockIcon).setOnLongClickListener(longClickCaptor.capture());
388 verify(mLockIcon).setOnClickListener(clickCaptor.capture());
389
390 when(mAccessibilityController.isAccessibilityEnabled()).thenReturn(true);
391 clickCaptor.getValue().onClick(mLockIcon);
Lucas Dupind54f00e2019-05-06 17:44:03 -0700392 verify(mShadeController).animateCollapsePanels(anyInt(), eq(true));
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700393
394 longClickCaptor.getValue().onLongClick(mLockIcon);
395 verify(mLockPatternUtils).requireCredentialEntry(anyInt());
Lucas Dupinca88e5f2019-05-14 16:11:08 -0700396 verify(mKeyguardUpdateMonitor).onLockIconPressed();
Lucas Dupin0df60fe2019-04-23 10:19:27 -0700397 }
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700398
399 @Test
400 public void unlockMethodCache_listenerUpdatesIndication() {
401 createController();
402 String restingIndication = "Resting indication";
403 when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
404 mController.setRestingIndication(restingIndication);
405 mController.setVisible(true);
406 assertThat(mTextView.getText()).isEqualTo(mController.getTrustGrantedIndication());
407
408 reset(mKeyguardUpdateMonitor);
409 when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(false);
410 mController.onUnlockMethodStateChanged();
411 assertThat(mTextView.getText()).isEqualTo(restingIndication);
412 }
413
414 @Test
415 public void unlockMethodCache_listener() {
416 createController();
417 verify(mUnlockMethodCache).addListener(eq(mController));
418 verify(mStatusBarStateController).addCallback(eq(mController));
419 verify(mKeyguardUpdateMonitor, times(2)).registerCallback(any());
Lucas Dupin8e2fd012019-04-25 16:40:54 -0700420 }
Bartosz Fabianowski5f045002016-12-01 10:36:18 +0100421}