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