1 /* 2 * Copyright (C) 2023 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.systemui.statusbar; 18 19 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT; 20 21 import static com.android.systemui.flags.Flags.KEYGUARD_TALKBACK_FIX; 22 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; 23 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_TRANSIENT; 24 import static com.android.systemui.keyguard.ScreenLifecycle.SCREEN_ON; 25 26 import static com.google.common.truth.Truth.assertThat; 27 28 import static org.mockito.ArgumentMatchers.any; 29 import static org.mockito.ArgumentMatchers.anyBoolean; 30 import static org.mockito.ArgumentMatchers.anyInt; 31 import static org.mockito.ArgumentMatchers.anyString; 32 import static org.mockito.ArgumentMatchers.eq; 33 import static org.mockito.Mockito.clearInvocations; 34 import static org.mockito.Mockito.mock; 35 import static org.mockito.Mockito.never; 36 import static org.mockito.Mockito.reset; 37 import static org.mockito.Mockito.verify; 38 import static org.mockito.Mockito.when; 39 40 import static java.util.Collections.emptySet; 41 42 import android.app.AlarmManager; 43 import android.app.Instrumentation; 44 import android.app.admin.DevicePolicyManager; 45 import android.app.admin.DevicePolicyResourcesManager; 46 import android.app.trust.TrustManager; 47 import android.content.BroadcastReceiver; 48 import android.content.ComponentName; 49 import android.content.Context; 50 import android.hardware.fingerprint.FingerprintManager; 51 import android.os.Looper; 52 import android.os.UserManager; 53 import android.provider.DeviceConfig; 54 import android.testing.TestableLooper; 55 import android.view.ViewGroup; 56 import android.view.accessibility.AccessibilityManager; 57 58 import androidx.test.InstrumentationRegistry; 59 60 import com.android.internal.app.IBatteryStats; 61 import com.android.internal.widget.LockPatternUtils; 62 import com.android.keyguard.KeyguardUpdateMonitor; 63 import com.android.keyguard.KeyguardUpdateMonitorCallback; 64 import com.android.keyguard.logging.KeyguardLogger; 65 import com.android.systemui.SysuiTestCase; 66 import com.android.systemui.biometrics.AuthController; 67 import com.android.systemui.biometrics.FaceHelpMessageDeferral; 68 import com.android.systemui.biometrics.FaceHelpMessageDeferralFactory; 69 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor; 70 import com.android.systemui.bouncer.domain.interactor.BouncerMessageInteractor; 71 import com.android.systemui.broadcast.BroadcastDispatcher; 72 import com.android.systemui.deviceentry.domain.interactor.BiometricMessageInteractor; 73 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor; 74 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFingerprintAuthInteractor; 75 import com.android.systemui.dock.DockManager; 76 import com.android.systemui.flags.FakeFeatureFlags; 77 import com.android.systemui.keyguard.KeyguardIndication; 78 import com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController; 79 import com.android.systemui.keyguard.ScreenLifecycle; 80 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory; 81 import com.android.systemui.keyguard.util.IndicationHelper; 82 import com.android.systemui.plugins.FalsingManager; 83 import com.android.systemui.plugins.statusbar.StatusBarStateController; 84 import com.android.systemui.res.R; 85 import com.android.systemui.settings.UserTracker; 86 import com.android.systemui.statusbar.phone.KeyguardBypassController; 87 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView; 88 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager; 89 import com.android.systemui.statusbar.policy.KeyguardStateController; 90 import com.android.systemui.util.concurrency.FakeExecutor; 91 import com.android.systemui.util.time.FakeSystemClock; 92 import com.android.systemui.util.wakelock.WakeLockFake; 93 94 import kotlinx.coroutines.flow.StateFlow; 95 96 import org.junit.After; 97 import org.junit.Before; 98 import org.mockito.ArgumentCaptor; 99 import org.mockito.Captor; 100 import org.mockito.Mock; 101 import org.mockito.MockitoAnnotations; 102 103 public class KeyguardIndicationControllerBaseTest extends SysuiTestCase { 104 105 protected static final String ORGANIZATION_NAME = "organization"; 106 107 protected static final ComponentName DEVICE_OWNER_COMPONENT = new ComponentName( 108 "com.android.foo", 109 "bar"); 110 111 protected static final int TEST_STRING_RES = R.string.keyguard_indication_trust_unlocked; 112 113 protected String mDisclosureWithOrganization; 114 protected String mDisclosureGeneric; 115 protected String mFinancedDisclosureWithOrganization; 116 117 @Mock 118 protected DevicePolicyManager mDevicePolicyManager; 119 @Mock 120 protected DevicePolicyResourcesManager mDevicePolicyResourcesManager; 121 @Mock 122 protected ViewGroup mIndicationArea; 123 @Mock 124 protected KeyguardStateController mKeyguardStateController; 125 @Mock 126 protected KeyguardIndicationTextView mIndicationAreaBottom; 127 @Mock 128 protected BroadcastDispatcher mBroadcastDispatcher; 129 @Mock 130 protected StatusBarStateController mStatusBarStateController; 131 @Mock 132 protected KeyguardUpdateMonitor mKeyguardUpdateMonitor; 133 @Mock 134 protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 135 @Mock 136 protected UserManager mUserManager; 137 @Mock 138 protected IBatteryStats mIBatteryStats; 139 @Mock 140 protected DockManager mDockManager; 141 @Mock 142 protected KeyguardIndicationRotateTextViewController mRotateTextViewController; 143 @Mock 144 protected FalsingManager mFalsingManager; 145 @Mock 146 protected LockPatternUtils mLockPatternUtils; 147 @Mock 148 protected KeyguardBypassController mKeyguardBypassController; 149 @Mock 150 protected AccessibilityManager mAccessibilityManager; 151 @Mock 152 protected FaceHelpMessageDeferralFactory mFaceHelpMessageDeferralFactory; 153 @Mock 154 protected FaceHelpMessageDeferral mFaceHelpMessageDeferral; 155 @Mock 156 protected AlternateBouncerInteractor mAlternateBouncerInteractor; 157 @Mock 158 protected BiometricMessageInteractor mBiometricMessageInteractor; 159 @Mock 160 protected DeviceEntryFaceAuthInteractor mDeviceEntryFaceAuthInteractor; 161 @Mock 162 protected DeviceEntryFingerprintAuthInteractor mDeviceEntryFingerprintAuthInteractor; 163 @Mock 164 protected ScreenLifecycle mScreenLifecycle; 165 @Mock 166 protected AuthController mAuthController; 167 @Mock 168 protected AlarmManager mAlarmManager; 169 @Mock 170 protected UserTracker mUserTracker; 171 @Captor 172 protected ArgumentCaptor<DockManager.AlignmentStateListener> mAlignmentListener; 173 @Captor 174 protected ArgumentCaptor<StatusBarStateController.StateListener> mStatusBarStateListenerCaptor; 175 @Captor 176 protected ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor; 177 @Captor 178 protected ArgumentCaptor<KeyguardIndication> mKeyguardIndicationCaptor; 179 @Captor 180 protected ArgumentCaptor<KeyguardUpdateMonitorCallback> mKeyguardUpdateMonitorCallbackCaptor; 181 @Captor 182 protected ArgumentCaptor<KeyguardStateController.Callback> 183 mKeyguardStateControllerCallbackCaptor; 184 @Captor 185 protected ArgumentCaptor<ScreenLifecycle.Observer> mScreenObserverCaptor; 186 protected KeyguardStateController.Callback mKeyguardStateControllerCallback; 187 protected KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback; 188 protected StatusBarStateController.StateListener mStatusBarStateListener; 189 protected ScreenLifecycle.Observer mScreenObserver; 190 protected BroadcastReceiver mBroadcastReceiver; 191 protected IndicationHelper mIndicationHelper; 192 protected FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock()); 193 protected TestableLooper mTestableLooper; 194 protected final int mCurrentUserId = 1; 195 196 protected KeyguardIndicationTextView mTextView; // AOD text 197 198 protected KeyguardIndicationController mController; 199 protected WakeLockFake.Builder mWakeLockBuilder; 200 protected WakeLockFake mWakeLock; 201 protected Instrumentation mInstrumentation; 202 protected FakeFeatureFlags mFlags; 203 204 @Before setUp()205 public void setUp() throws Exception { 206 MockitoAnnotations.initMocks(this); 207 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 208 mTestableLooper = TestableLooper.get(this); 209 mTextView = new KeyguardIndicationTextView(mContext); 210 mTextView.setAnimationsEnabled(false); 211 212 // TODO(b/259908270): remove 213 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_DEVICE_POLICY_MANAGER, 214 DevicePolicyManager.ADD_ISFINANCED_DEVICE_FLAG, "true", 215 /* makeDefault= */ false); 216 mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager); 217 mContext.addMockSystemService(UserManager.class, mUserManager); 218 mContext.addMockSystemService(Context.TRUST_SERVICE, mock(TrustManager.class)); 219 mContext.addMockSystemService(Context.FINGERPRINT_SERVICE, mock(FingerprintManager.class)); 220 mDisclosureWithOrganization = mContext.getString(R.string.do_disclosure_with_name, 221 ORGANIZATION_NAME); 222 mDisclosureGeneric = mContext.getString(R.string.do_disclosure_generic); 223 mFinancedDisclosureWithOrganization = mContext.getString( 224 R.string.do_financed_disclosure_with_name, ORGANIZATION_NAME); 225 226 when(mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); 227 when(mScreenLifecycle.getScreenState()).thenReturn(SCREEN_ON); 228 when(mKeyguardUpdateMonitor.isUserUnlocked(anyInt())).thenReturn(true); 229 230 when(mIndicationArea.findViewById(R.id.keyguard_indication_text_bottom)) 231 .thenReturn(mIndicationAreaBottom); 232 when(mIndicationArea.findViewById(R.id.keyguard_indication_text)).thenReturn(mTextView); 233 234 when(mDevicePolicyManager.getResources()).thenReturn(mDevicePolicyResourcesManager); 235 when(mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser()) 236 .thenReturn(DEVICE_OWNER_COMPONENT); 237 when(mDevicePolicyManager.isFinancedDevice()).thenReturn(false); 238 // TODO(b/259908270): remove 239 when(mDevicePolicyManager.getDeviceOwnerType(DEVICE_OWNER_COMPONENT)) 240 .thenReturn(DEVICE_OWNER_TYPE_DEFAULT); 241 242 when(mDevicePolicyResourcesManager.getString(anyString(), any())) 243 .thenReturn(mDisclosureGeneric); 244 when(mDevicePolicyResourcesManager.getString(anyString(), any(), anyString())) 245 .thenReturn(mDisclosureWithOrganization); 246 when(mUserTracker.getUserId()).thenReturn(mCurrentUserId); 247 when(mBiometricMessageInteractor.getCoExFaceAcquisitionMsgIdsToShow()) 248 .thenReturn(mock(StateFlow.class)); 249 250 when(mFaceHelpMessageDeferralFactory.create()).thenReturn(mFaceHelpMessageDeferral); 251 when(mDeviceEntryFingerprintAuthInteractor.isEngaged()).thenReturn(mock(StateFlow.class)); 252 253 mIndicationHelper = new IndicationHelper(mKeyguardUpdateMonitor); 254 255 mWakeLock = new WakeLockFake(); 256 mWakeLockBuilder = new WakeLockFake.Builder(mContext); 257 mWakeLockBuilder.setWakeLock(mWakeLock); 258 } 259 260 @After tearDown()261 public void tearDown() throws Exception { 262 mTextView.setAnimationsEnabled(true); 263 if (mController != null) { 264 mController.destroy(); 265 mController = null; 266 } 267 } 268 createController()269 protected void createController() { 270 if (Looper.myLooper() == null) { 271 Looper.prepare(); 272 } 273 274 mFlags = new FakeFeatureFlags(); 275 mFlags.set(KEYGUARD_TALKBACK_FIX, true); 276 mFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false); 277 mController = new KeyguardIndicationController( 278 mContext, 279 mTestableLooper.getLooper(), 280 mWakeLockBuilder, 281 mKeyguardStateController, mStatusBarStateController, mKeyguardUpdateMonitor, 282 mDockManager, mBroadcastDispatcher, mDevicePolicyManager, mIBatteryStats, 283 mUserManager, mExecutor, mExecutor, mFalsingManager, 284 mAuthController, mLockPatternUtils, mScreenLifecycle, 285 mKeyguardBypassController, mAccessibilityManager, 286 mFaceHelpMessageDeferralFactory, mock(KeyguardLogger.class), 287 mAlternateBouncerInteractor, 288 mAlarmManager, 289 mUserTracker, 290 mock(BouncerMessageInteractor.class), 291 mFlags, 292 mIndicationHelper, 293 KeyguardInteractorFactory.create(mFlags).getKeyguardInteractor(), 294 mBiometricMessageInteractor, 295 mDeviceEntryFingerprintAuthInteractor, 296 mDeviceEntryFaceAuthInteractor 297 ); 298 mController.init(); 299 mController.setIndicationArea(mIndicationArea); 300 mController.mCoExAcquisitionMsgIdsToShowCallback.accept(emptySet()); 301 verify(mStatusBarStateController).addCallback(mStatusBarStateListenerCaptor.capture()); 302 mStatusBarStateListener = mStatusBarStateListenerCaptor.getValue(); 303 verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiverCaptor.capture(), any()); 304 mBroadcastReceiver = mBroadcastReceiverCaptor.getValue(); 305 mController.mRotateTextViewController = mRotateTextViewController; 306 mController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); 307 clearInvocations(mIBatteryStats); 308 309 verify(mKeyguardStateController).addCallback( 310 mKeyguardStateControllerCallbackCaptor.capture()); 311 mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue(); 312 313 verify(mKeyguardUpdateMonitor).registerCallback( 314 mKeyguardUpdateMonitorCallbackCaptor.capture()); 315 mKeyguardUpdateMonitorCallback = mKeyguardUpdateMonitorCallbackCaptor.getValue(); 316 317 verify(mScreenLifecycle).addObserver(mScreenObserverCaptor.capture()); 318 mScreenObserver = mScreenObserverCaptor.getValue(); 319 320 mExecutor.runAllReady(); 321 reset(mRotateTextViewController); 322 } 323 verifyNoMessage(int type)324 void verifyNoMessage(int type) { 325 if (type == INDICATION_TYPE_TRANSIENT) { 326 verify(mRotateTextViewController, never()).showTransient(anyString()); 327 } else { 328 verify(mRotateTextViewController, never()).updateIndication(eq(type), 329 any(KeyguardIndication.class), anyBoolean()); 330 } 331 } 332 verifyIndicationShown(int indicationType, String message)333 void verifyIndicationShown(int indicationType, String message) { 334 verify(mRotateTextViewController) 335 .updateIndication(eq(indicationType), 336 mKeyguardIndicationCaptor.capture(), 337 eq(true)); 338 assertThat(mKeyguardIndicationCaptor.getValue().getMessage().toString()) 339 .isEqualTo(message); 340 } 341 } 342