1 /* 2 * Copyright (C) 2021 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.server.policy; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.mockito.Mockito.eq; 22 import static org.mockito.Mockito.mock; 23 import static org.mockito.Mockito.never; 24 import static org.mockito.Mockito.verify; 25 import static org.mockito.Mockito.when; 26 27 import android.content.pm.PackageManager; 28 import android.hardware.biometrics.BiometricStateListener; 29 import android.hardware.fingerprint.FingerprintManager; 30 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 31 import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; 32 import android.os.Handler; 33 import android.os.PowerManager; 34 import android.os.test.TestLooper; 35 import android.test.suitebuilder.annotation.SmallTest; 36 import android.testing.AndroidTestingRunner; 37 import android.testing.TestableContext; 38 import android.testing.TestableResources; 39 import android.view.Window; 40 41 import androidx.test.InstrumentationRegistry; 42 43 import com.android.internal.R; 44 45 import org.junit.Before; 46 import org.junit.Rule; 47 import org.junit.Test; 48 import org.junit.runner.RunWith; 49 import org.mockito.ArgumentCaptor; 50 import org.mockito.Mock; 51 import org.mockito.MockitoAnnotations; 52 53 import java.util.List; 54 55 /** 56 * Unit tests for {@link SideFpsEventHandler}. 57 * 58 * <p>Run with <code>atest SideFpsEventHandlerTest</code>. 59 */ 60 @SmallTest 61 @RunWith(AndroidTestingRunner.class) 62 public class SideFpsEventHandlerTest { 63 64 private static final List<Integer> sAllStates = 65 List.of( 66 BiometricStateListener.STATE_IDLE, 67 BiometricStateListener.STATE_ENROLLING, 68 BiometricStateListener.STATE_KEYGUARD_AUTH, 69 BiometricStateListener.STATE_BP_AUTH, 70 BiometricStateListener.STATE_AUTH_OTHER); 71 72 private static final Integer AUTO_DISMISS_DIALOG = 500; 73 74 @Rule 75 public TestableContext mContext = 76 new TestableContext(InstrumentationRegistry.getContext(), null); 77 78 @Mock 79 private PackageManager mPackageManager; 80 @Mock 81 private FingerprintManager mFingerprintManager; 82 @Mock 83 private SideFpsToast mDialog; 84 @Mock 85 private Window mWindow; 86 87 private final TestLooper mLooper = new TestLooper(); 88 private SideFpsEventHandler mEventHandler; 89 private BiometricStateListener mBiometricStateListener; 90 91 @Before setup()92 public void setup() { 93 MockitoAnnotations.initMocks(this); 94 95 mContext.addMockSystemService(PackageManager.class, mPackageManager); 96 mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); 97 TestableResources resources = mContext.getOrCreateTestableResources(); 98 resources.addOverride(R.integer.config_sideFpsToastTimeout, AUTO_DISMISS_DIALOG); 99 100 when(mDialog.getWindow()).thenReturn(mWindow); 101 102 mEventHandler = 103 new SideFpsEventHandler( 104 mContext, 105 new Handler(mLooper.getLooper()), 106 mContext.getSystemService(PowerManager.class), 107 (ctx) -> mDialog); 108 } 109 110 @Test ignoresWithoutFingerprintFeature()111 public void ignoresWithoutFingerprintFeature() { 112 when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) 113 .thenReturn(false); 114 115 assertThat(mEventHandler.shouldConsumeSinglePress(60L)).isFalse(); 116 117 mLooper.dispatchAll(); 118 verify(mDialog, never()).show(); 119 } 120 121 @Test ignoresWithoutSfps()122 public void ignoresWithoutSfps() throws Exception { 123 setupWithSensor(false /* hasSfps */, true /* initialized */); 124 125 for (int state : sAllStates) { 126 setBiometricState(state); 127 assertThat(mEventHandler.shouldConsumeSinglePress(200L)).isFalse(); 128 129 mLooper.dispatchAll(); 130 verify(mDialog, never()).show(); 131 } 132 } 133 134 @Test ignoresWhileWaitingForSfps()135 public void ignoresWhileWaitingForSfps() throws Exception { 136 setupWithSensor(true /* hasSfps */, false /* initialized */); 137 138 for (int state : sAllStates) { 139 setBiometricState(state); 140 assertThat(mEventHandler.shouldConsumeSinglePress(400L)).isFalse(); 141 142 mLooper.dispatchAll(); 143 verify(mDialog, never()).show(); 144 } 145 } 146 147 @Test ignoresWhenIdleOrUnknown()148 public void ignoresWhenIdleOrUnknown() throws Exception { 149 setupWithSensor(true /* hasSidefps */, true /* initialized */); 150 151 setBiometricState(BiometricStateListener.STATE_IDLE); 152 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse(); 153 154 setBiometricState(BiometricStateListener.STATE_AUTH_OTHER); 155 assertThat(mEventHandler.shouldConsumeSinglePress(90000L)).isFalse(); 156 157 mLooper.dispatchAll(); 158 verify(mDialog, never()).show(); 159 } 160 161 @Test ignoresOnKeyguard()162 public void ignoresOnKeyguard() throws Exception { 163 setupWithSensor(true /* hasSfps */, true /* initialized */); 164 165 setBiometricState(BiometricStateListener.STATE_KEYGUARD_AUTH); 166 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isFalse(); 167 168 mLooper.dispatchAll(); 169 verify(mDialog, never()).show(); 170 } 171 172 @Test doesNotpromptWhenBPisActive()173 public void doesNotpromptWhenBPisActive() throws Exception { 174 setupWithSensor(true /* hasSideFps */, true /* initialized */); 175 176 setBiometricState(BiometricStateListener.STATE_BP_AUTH); 177 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); 178 179 mLooper.dispatchAll(); 180 verify(mDialog, never()).show(); 181 } 182 183 @Test promptsWhenEnrolling()184 public void promptsWhenEnrolling() throws Exception { 185 setupWithSensor(true /* hasSfps */, true /* initialized */); 186 187 setBiometricState(BiometricStateListener.STATE_ENROLLING); 188 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); 189 190 mLooper.dispatchAll(); 191 verify(mDialog).show(); 192 } 193 194 @Test dialogDismissesAfterTime()195 public void dialogDismissesAfterTime() throws Exception { 196 setupWithSensor(true /* hasSfps */, true /* initialized */); 197 198 setBiometricState(BiometricStateListener.STATE_ENROLLING); 199 when(mDialog.isShowing()).thenReturn(true); 200 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); 201 202 mLooper.dispatchAll(); 203 verify(mDialog).show(); 204 mLooper.moveTimeForward(AUTO_DISMISS_DIALOG); 205 mLooper.dispatchAll(); 206 verify(mDialog).dismiss(); 207 } 208 209 @Test dialogDoesNotDismissOnSensorTouch()210 public void dialogDoesNotDismissOnSensorTouch() throws Exception { 211 setupWithSensor(true /* hasSfps */, true /* initialized */); 212 213 setBiometricState(BiometricStateListener.STATE_ENROLLING); 214 when(mDialog.isShowing()).thenReturn(true); 215 assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); 216 217 mLooper.dispatchAll(); 218 verify(mDialog).show(); 219 220 mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); 221 mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1); 222 mLooper.dispatchAll(); 223 224 verify(mDialog, never()).dismiss(); 225 } 226 setBiometricState(@iometricStateListener.State int newState)227 private void setBiometricState(@BiometricStateListener.State int newState) { 228 if (mBiometricStateListener != null) { 229 mBiometricStateListener.onStateChanged(newState); 230 mLooper.dispatchAll(); 231 } 232 } 233 setupWithSensor(boolean hasSfps, boolean initialized)234 private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception { 235 when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) 236 .thenReturn(true); 237 when(mFingerprintManager.isPowerbuttonFps()).thenReturn(hasSfps); 238 mEventHandler.onFingerprintSensorReady(); 239 240 ArgumentCaptor<IFingerprintAuthenticatorsRegisteredCallback> fpCallbackCaptor = 241 ArgumentCaptor.forClass(IFingerprintAuthenticatorsRegisteredCallback.class); 242 verify(mFingerprintManager).addAuthenticatorsRegisteredCallback(fpCallbackCaptor.capture()); 243 if (initialized) { 244 fpCallbackCaptor 245 .getValue() 246 .onAllAuthenticatorsRegistered( 247 List.of(mock(FingerprintSensorPropertiesInternal.class))); 248 if (hasSfps) { 249 ArgumentCaptor<BiometricStateListener> captor = 250 ArgumentCaptor.forClass(BiometricStateListener.class); 251 verify(mFingerprintManager).registerBiometricStateListener(captor.capture()); 252 mBiometricStateListener = captor.getValue(); 253 } 254 } 255 } 256 } 257