1 /* 2 * Copyright (C) 2020 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.keyguard; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.ArgumentMatchers.any; 22 import static org.mockito.ArgumentMatchers.anyInt; 23 import static org.mockito.ArgumentMatchers.eq; 24 import static org.mockito.Mockito.mock; 25 import static org.mockito.Mockito.never; 26 import static org.mockito.Mockito.reset; 27 import static org.mockito.Mockito.verify; 28 import static org.mockito.Mockito.verifyNoMoreInteractions; 29 import static org.mockito.Mockito.when; 30 31 import android.os.SystemClock; 32 import android.platform.test.annotations.DisableFlags; 33 import android.platform.test.annotations.EnableFlags; 34 import android.testing.TestableLooper.RunWithLooper; 35 import android.view.KeyEvent; 36 37 import androidx.test.ext.junit.runners.AndroidJUnit4; 38 import androidx.test.filters.SmallTest; 39 40 import com.android.internal.util.LatencyTracker; 41 import com.android.internal.widget.LockPatternUtils; 42 import com.android.keyguard.KeyguardAbsKeyInputView.KeyDownListener; 43 import com.android.keyguard.KeyguardSecurityModel.SecurityMode; 44 import com.android.systemui.Flags; 45 import com.android.systemui.SysuiTestCase; 46 import com.android.systemui.bouncer.ui.helper.BouncerHapticPlayer; 47 import com.android.systemui.classifier.FalsingCollector; 48 import com.android.systemui.classifier.FalsingCollectorFake; 49 import com.android.systemui.flags.FakeFeatureFlags; 50 import com.android.systemui.haptics.msdl.FakeMSDLPlayer; 51 import com.android.systemui.kosmos.KosmosJavaAdapter; 52 import com.android.systemui.res.R; 53 import com.android.systemui.user.domain.interactor.SelectedUserInteractor; 54 55 import com.google.android.msdl.data.model.MSDLToken; 56 57 import org.junit.Before; 58 import org.junit.Test; 59 import org.junit.runner.RunWith; 60 import org.mockito.ArgumentCaptor; 61 import org.mockito.Mock; 62 import org.mockito.MockitoAnnotations; 63 64 @SmallTest 65 @RunWith(AndroidJUnit4.class) 66 @RunWithLooper 67 public class KeyguardAbsKeyInputViewControllerTest extends SysuiTestCase { 68 69 @Mock 70 private KeyguardAbsKeyInputView mAbsKeyInputView; 71 @Mock 72 private PasswordTextView mPasswordEntry; 73 @Mock 74 private BouncerKeyguardMessageArea mKeyguardMessageArea; 75 @Mock 76 private KeyguardUpdateMonitor mKeyguardUpdateMonitor; 77 @Mock 78 private SecurityMode mSecurityMode; 79 @Mock 80 private LockPatternUtils mLockPatternUtils; 81 @Mock 82 private KeyguardSecurityCallback mKeyguardSecurityCallback; 83 @Mock 84 private KeyguardMessageAreaController.Factory mKeyguardMessageAreaControllerFactory; 85 @Mock 86 private KeyguardMessageAreaController mKeyguardMessageAreaController; 87 @Mock 88 private LatencyTracker mLatencyTracker; 89 private final FalsingCollector mFalsingCollector = new FalsingCollectorFake(); 90 @Mock 91 private EmergencyButtonController mEmergencyButtonController; 92 93 private FakeFeatureFlags mFeatureFlags; 94 @Mock 95 private SelectedUserInteractor mSelectedUserInteractor; 96 @Mock 97 private UserActivityNotifier mUserActivityNotifier; 98 private KeyguardAbsKeyInputViewController mKeyguardAbsKeyInputViewController; 99 private KosmosJavaAdapter mKosmosJavaAdapter = new KosmosJavaAdapter(this); 100 private final BouncerHapticPlayer mBouncerHapticPlayer = 101 mKosmosJavaAdapter.getBouncerHapticHelper(); 102 private final FakeMSDLPlayer mMSDLPlayer = mKosmosJavaAdapter.getMsdlPlayer(); 103 104 @Before setup()105 public void setup() { 106 MockitoAnnotations.initMocks(this); 107 when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class))) 108 .thenReturn(mKeyguardMessageAreaController); 109 when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1); 110 when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry); 111 when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true); 112 when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area)) 113 .thenReturn(mKeyguardMessageArea); 114 when(mAbsKeyInputView.getResources()).thenReturn(getContext().getResources()); 115 mFeatureFlags = new FakeFeatureFlags(); 116 mKeyguardAbsKeyInputViewController = createTestObject(); 117 mKeyguardAbsKeyInputViewController.init(); 118 reset(mKeyguardMessageAreaController); // Clear out implicit call to init. 119 } 120 createTestObject()121 private KeyguardAbsKeyInputViewController createTestObject() { 122 return new KeyguardAbsKeyInputViewController(mAbsKeyInputView, 123 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback, 124 mKeyguardMessageAreaControllerFactory, mLatencyTracker, mFalsingCollector, 125 mEmergencyButtonController, mFeatureFlags, mSelectedUserInteractor, 126 mBouncerHapticPlayer, mUserActivityNotifier) { 127 @Override 128 void resetState() { 129 } 130 131 @Override 132 public void onResume(int reason) { 133 super.onResume(reason); 134 } 135 136 @Override 137 protected int getInitialMessageResId() { 138 return 0; 139 } 140 }; 141 } 142 143 @Test 144 @EnableFlags(Flags.FLAG_REVAMPED_BOUNCER_MESSAGES) 145 public void withFeatureFlagOn_oldMessage_isHidden() { 146 KeyguardAbsKeyInputViewController underTest = createTestObject(); 147 148 underTest.init(); 149 150 verify(mKeyguardMessageAreaController).disable(); 151 } 152 153 @Test 154 public void onKeyDown_clearsSecurityMessage() { 155 ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor = 156 ArgumentCaptor.forClass(KeyDownListener.class); 157 verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture()); 158 onKeyDownListenerArgumentCaptor.getValue().onKeyDown( 159 KeyEvent.KEYCODE_0, mock(KeyEvent.class)); 160 verify(mKeyguardSecurityCallback).userActivity(); 161 verify(mKeyguardMessageAreaController).setMessage(eq("")); 162 } 163 164 @Test 165 public void onKeyDown_noSecurityMessageInteraction() { 166 ArgumentCaptor<KeyDownListener> onKeyDownListenerArgumentCaptor = 167 ArgumentCaptor.forClass(KeyDownListener.class); 168 verify(mAbsKeyInputView).setKeyDownListener(onKeyDownListenerArgumentCaptor.capture()); 169 onKeyDownListenerArgumentCaptor.getValue().onKeyDown( 170 KeyEvent.KEYCODE_UNKNOWN, mock(KeyEvent.class)); 171 verifyNoMoreInteractions(mKeyguardSecurityCallback); 172 verifyNoMoreInteractions(mKeyguardMessageAreaController); 173 } 174 175 @Test 176 public void onPromptReasonNone_doesNotSetMessage() { 177 mKeyguardAbsKeyInputViewController.showPromptReason(0); 178 verify(mKeyguardMessageAreaController, never()).setMessage( 179 getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), 180 false); 181 } 182 183 @Test 184 public void onPromptReason_setsMessage() { 185 when(mAbsKeyInputView.getPromptReasonStringRes(1)).thenReturn( 186 R.string.kg_prompt_reason_restart_password); 187 mKeyguardAbsKeyInputViewController.showPromptReason(1); 188 verify(mKeyguardMessageAreaController).setMessage( 189 getContext().getResources().getString(R.string.kg_prompt_reason_restart_password), 190 false); 191 } 192 193 194 @Test 195 public void testReset() { 196 mKeyguardAbsKeyInputViewController.reset(); 197 verify(mKeyguardMessageAreaController).setMessage("", false); 198 } 199 200 @Test 201 public void testOnViewAttached() { 202 reset(mLockPatternUtils); 203 mKeyguardAbsKeyInputViewController.onViewAttached(); 204 verify(mLockPatternUtils).getLockoutAttemptDeadline(anyInt()); 205 } 206 207 @Test 208 public void testLockedOut_verifyPasswordAndUnlock_doesNotEnableViewInput() { 209 mKeyguardAbsKeyInputViewController.handleAttemptLockout(SystemClock.elapsedRealtime()); 210 verify(mAbsKeyInputView).setPasswordEntryInputEnabled(false); 211 verify(mAbsKeyInputView).setPasswordEntryEnabled(false); 212 verify(mAbsKeyInputView, never()).setPasswordEntryInputEnabled(true); 213 verify(mAbsKeyInputView, never()).setPasswordEntryEnabled(true); 214 } 215 216 @Test 217 @EnableFlags(Flags.FLAG_MSDL_FEEDBACK) 218 public void onPasswordChecked_withMSDLFeedback_withMatch_playsUnlockToken() { 219 mKeyguardAbsKeyInputViewController.onPasswordChecked(0, true, 100, true); 220 assertThat(mMSDLPlayer.getLatestTokenPlayed()).isEqualTo(MSDLToken.UNLOCK); 221 } 222 223 @Test 224 @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) 225 public void onPasswordChecked_withoutMSDLFeedback_withMatch_doesNotPlayToken() { 226 mKeyguardAbsKeyInputViewController.onPasswordChecked(0, true, 100, true); 227 assertThat(mMSDLPlayer.getLatestTokenPlayed()).isNull(); 228 } 229 230 @Test 231 @EnableFlags(Flags.FLAG_MSDL_FEEDBACK) 232 public void onPasswordChecked_withMSDLFeedback_withoutMatch_playsFailureToken() { 233 mKeyguardAbsKeyInputViewController.onPasswordChecked(0, false, 100, true); 234 assertThat(mMSDLPlayer.getLatestTokenPlayed()).isEqualTo(MSDLToken.FAILURE); 235 } 236 237 @Test 238 @DisableFlags(Flags.FLAG_MSDL_FEEDBACK) 239 public void onPasswordChecked_withoutMSDLFeedback_withoutMatch_doesNotPlayToken() { 240 mKeyguardAbsKeyInputViewController.onPasswordChecked(0, false, 100, true); 241 assertThat(mMSDLPlayer.getLatestTokenPlayed()).isNull(); 242 } 243 } 244