Loading services/core/java/com/android/server/policy/SideFpsEventHandler.java +13 −1 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.util.Log; import android.view.View; import android.view.View; import android.view.Window; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -66,6 +67,7 @@ public class SideFpsEventHandler implements View.OnClickListener { private final int mDismissDialogTimeout; private final int mDismissDialogTimeout; @Nullable @Nullable private SideFpsToast mDialog; private SideFpsToast mDialog; private final AccessibilityManager mAccessibilityManager; private final Runnable mTurnOffDialog = private final Runnable mTurnOffDialog = () -> { () -> { dismissDialog("mTurnOffDialog"); dismissDialog("mTurnOffDialog"); Loading Loading @@ -96,6 +98,7 @@ public class SideFpsEventHandler implements View.OnClickListener { DialogProvider provider) { DialogProvider provider) { mContext = context; mContext = context; mHandler = handler; mHandler = handler; mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mPowerManager = powerManager; mPowerManager = powerManager; mBiometricState = STATE_IDLE; mBiometricState = STATE_IDLE; mSideFpsEventHandlerReady = new AtomicBoolean(false); mSideFpsEventHandlerReady = new AtomicBoolean(false); Loading Loading @@ -157,7 +160,9 @@ public class SideFpsEventHandler implements View.OnClickListener { mHandler.removeCallbacks(mTurnOffDialog); mHandler.removeCallbacks(mTurnOffDialog); } } showDialog(eventTime, "Enroll Power Press"); showDialog(eventTime, "Enroll Power Press"); if (!mAccessibilityManager.isEnabled()) { mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout); mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout); } }); }); return true; return true; case STATE_BP_AUTH: case STATE_BP_AUTH: Loading Loading @@ -231,6 +236,10 @@ public class SideFpsEventHandler implements View.OnClickListener { public void onBiometricAction( public void onBiometricAction( @BiometricStateListener.Action int action) { @BiometricStateListener.Action int action) { Log.d(TAG, "onBiometricAction " + action); Log.d(TAG, "onBiometricAction " + action); if (mAccessibilityManager != null && mAccessibilityManager.isEnabled()) { dismissDialog("mTurnOffDialog"); } } } }); }); mSideFpsEventHandlerReady.set(true); mSideFpsEventHandlerReady.set(true); Loading @@ -256,6 +265,9 @@ public class SideFpsEventHandler implements View.OnClickListener { mLastPowerPressTime = time; mLastPowerPressTime = time; mDialog.show(); mDialog.show(); mDialog.setOnClickListener(this); mDialog.setOnClickListener(this); if (mAccessibilityManager.isEnabled()) { mDialog.addAccessibilityDelegate(); } } } interface DialogProvider { interface DialogProvider { Loading services/core/java/com/android/server/policy/SideFpsToast.java +25 −1 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.policy; package com.android.server.policy; import android.annotation.NonNull; import android.app.Dialog; import android.app.Dialog; import android.content.Context; import android.content.Context; import android.os.Bundle; import android.os.Bundle; Loading @@ -23,6 +24,7 @@ import android.view.Gravity; import android.view.View; import android.view.View; import android.view.Window; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.widget.Button; import android.widget.Button; import com.android.internal.R; import com.android.internal.R; Loading @@ -34,7 +36,6 @@ import com.android.internal.R; * This dialog is used by {@link SideFpsEventHandler} * This dialog is used by {@link SideFpsEventHandler} */ */ public class SideFpsToast extends Dialog { public class SideFpsToast extends Dialog { SideFpsToast(Context context) { SideFpsToast(Context context) { super(context); super(context); } } Loading Loading @@ -66,4 +67,27 @@ public class SideFpsToast extends Dialog { turnOffScreen.setOnClickListener(listener); turnOffScreen.setOnClickListener(listener); } } } } /** * When accessibility mode is on, add AccessibilityDelegate to dismiss dialog when focus is * moved away from the dialog. */ public void addAccessibilityDelegate() { final Button turnOffScreen = findViewById(R.id.turn_off_screen); if (turnOffScreen != null) { turnOffScreen.setAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityEvent(@NonNull View host, @NonNull AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED && isShowing()) { dismiss(); } super.onInitializeAccessibilityEvent(host, event); } }); } } } } services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java +58 −9 Original line number Original line Diff line number Diff line Loading @@ -31,11 +31,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager; import android.os.RemoteException; import android.os.test.TestLooper; import android.os.test.TestLooper; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableContext; import android.testing.TestableResources; import android.testing.TestableResources; import android.view.Window; import android.view.Window; import android.view.accessibility.AccessibilityManager; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; Loading @@ -48,7 +50,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.List; import java.util.List; Loading @@ -71,10 +74,16 @@ public class SideFpsEventHandlerTest { private static final Integer AUTO_DISMISS_DIALOG = 500; private static final Integer AUTO_DISMISS_DIALOG = 500; @Rule public MockitoRule rule = MockitoJUnit.rule(); @Rule @Rule public TestableContext mContext = public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext(), null); new TestableContext(InstrumentationRegistry.getContext(), null); private final AccessibilityManager mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); @Mock @Mock private PackageManager mPackageManager; private PackageManager mPackageManager; @Mock @Mock Loading @@ -89,9 +98,8 @@ public class SideFpsEventHandlerTest { private BiometricStateListener mBiometricStateListener; private BiometricStateListener mBiometricStateListener; @Before @Before public void setup() { public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); disableAccessibility(); mContext.addMockSystemService(PackageManager.class, mPackageManager); mContext.addMockSystemService(PackageManager.class, mPackageManager); mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); TestableResources resources = mContext.getOrCreateTestableResources(); TestableResources resources = mContext.getOrCreateTestableResources(); Loading Loading @@ -192,9 +200,8 @@ public class SideFpsEventHandlerTest { } } @Test @Test public void dialogDismissesAfterTime() throws Exception { public void dialogDismissesAfterTime_accessibilityDisabled() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); Loading @@ -207,9 +214,23 @@ public class SideFpsEventHandlerTest { } } @Test @Test public void dialogDoesNotDismissOnSensorTouch() throws Exception { public void dialogDoesNotDismissAfterTime_accessibilityEnabled() throws Exception { enableAccessibility(); setupWithSensor(true /* hasSfps */, true /* initialized */); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); mLooper.dispatchAll(); verify(mDialog).show(); mLooper.moveTimeForward(AUTO_DISMISS_DIALOG); mLooper.dispatchAll(); verify(mDialog, never()).dismiss(); } @Test public void dialogDoesNotDismissOnSensorTouch_accessibilityDisabled() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); Loading @@ -218,12 +239,26 @@ public class SideFpsEventHandlerTest { verify(mDialog).show(); verify(mDialog).show(); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1); mLooper.dispatchAll(); mLooper.dispatchAll(); verify(mDialog, never()).dismiss(); verify(mDialog, never()).dismiss(); } } @Test public void dialogDismissesOnSensorTouch_accessibilityEnabled() throws Exception { enableAccessibility(); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); mLooper.dispatchAll(); verify(mDialog).show(); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mLooper.dispatchAll(); verify(mDialog).dismiss(); } private void setBiometricState(@BiometricStateListener.State int newState) { private void setBiometricState(@BiometricStateListener.State int newState) { if (mBiometricStateListener != null) { if (mBiometricStateListener != null) { mBiometricStateListener.onStateChanged(newState); mBiometricStateListener.onStateChanged(newState); Loading @@ -231,6 +266,20 @@ public class SideFpsEventHandlerTest { } } } } private void enableAccessibility() throws RemoteException { if (mAccessibilityManager != null) { mAccessibilityManager.getClient().setState(1); mLooper.dispatchAll(); } } private void disableAccessibility() throws RemoteException { if (mAccessibilityManager != null) { mAccessibilityManager.getClient().setState(0); mLooper.dispatchAll(); } } private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception { private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception { when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) .thenReturn(true); .thenReturn(true); Loading Loading
services/core/java/com/android/server/policy/SideFpsEventHandler.java +13 −1 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ import android.util.Log; import android.view.View; import android.view.View; import android.view.Window; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import com.android.internal.R; import com.android.internal.R; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting; Loading Loading @@ -66,6 +67,7 @@ public class SideFpsEventHandler implements View.OnClickListener { private final int mDismissDialogTimeout; private final int mDismissDialogTimeout; @Nullable @Nullable private SideFpsToast mDialog; private SideFpsToast mDialog; private final AccessibilityManager mAccessibilityManager; private final Runnable mTurnOffDialog = private final Runnable mTurnOffDialog = () -> { () -> { dismissDialog("mTurnOffDialog"); dismissDialog("mTurnOffDialog"); Loading Loading @@ -96,6 +98,7 @@ public class SideFpsEventHandler implements View.OnClickListener { DialogProvider provider) { DialogProvider provider) { mContext = context; mContext = context; mHandler = handler; mHandler = handler; mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); mPowerManager = powerManager; mPowerManager = powerManager; mBiometricState = STATE_IDLE; mBiometricState = STATE_IDLE; mSideFpsEventHandlerReady = new AtomicBoolean(false); mSideFpsEventHandlerReady = new AtomicBoolean(false); Loading Loading @@ -157,7 +160,9 @@ public class SideFpsEventHandler implements View.OnClickListener { mHandler.removeCallbacks(mTurnOffDialog); mHandler.removeCallbacks(mTurnOffDialog); } } showDialog(eventTime, "Enroll Power Press"); showDialog(eventTime, "Enroll Power Press"); if (!mAccessibilityManager.isEnabled()) { mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout); mHandler.postDelayed(mTurnOffDialog, mDismissDialogTimeout); } }); }); return true; return true; case STATE_BP_AUTH: case STATE_BP_AUTH: Loading Loading @@ -231,6 +236,10 @@ public class SideFpsEventHandler implements View.OnClickListener { public void onBiometricAction( public void onBiometricAction( @BiometricStateListener.Action int action) { @BiometricStateListener.Action int action) { Log.d(TAG, "onBiometricAction " + action); Log.d(TAG, "onBiometricAction " + action); if (mAccessibilityManager != null && mAccessibilityManager.isEnabled()) { dismissDialog("mTurnOffDialog"); } } } }); }); mSideFpsEventHandlerReady.set(true); mSideFpsEventHandlerReady.set(true); Loading @@ -256,6 +265,9 @@ public class SideFpsEventHandler implements View.OnClickListener { mLastPowerPressTime = time; mLastPowerPressTime = time; mDialog.show(); mDialog.show(); mDialog.setOnClickListener(this); mDialog.setOnClickListener(this); if (mAccessibilityManager.isEnabled()) { mDialog.addAccessibilityDelegate(); } } } interface DialogProvider { interface DialogProvider { Loading
services/core/java/com/android/server/policy/SideFpsToast.java +25 −1 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.policy; package com.android.server.policy; import android.annotation.NonNull; import android.app.Dialog; import android.app.Dialog; import android.content.Context; import android.content.Context; import android.os.Bundle; import android.os.Bundle; Loading @@ -23,6 +24,7 @@ import android.view.Gravity; import android.view.View; import android.view.View; import android.view.Window; import android.view.Window; import android.view.WindowManager; import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.widget.Button; import android.widget.Button; import com.android.internal.R; import com.android.internal.R; Loading @@ -34,7 +36,6 @@ import com.android.internal.R; * This dialog is used by {@link SideFpsEventHandler} * This dialog is used by {@link SideFpsEventHandler} */ */ public class SideFpsToast extends Dialog { public class SideFpsToast extends Dialog { SideFpsToast(Context context) { SideFpsToast(Context context) { super(context); super(context); } } Loading Loading @@ -66,4 +67,27 @@ public class SideFpsToast extends Dialog { turnOffScreen.setOnClickListener(listener); turnOffScreen.setOnClickListener(listener); } } } } /** * When accessibility mode is on, add AccessibilityDelegate to dismiss dialog when focus is * moved away from the dialog. */ public void addAccessibilityDelegate() { final Button turnOffScreen = findViewById(R.id.turn_off_screen); if (turnOffScreen != null) { turnOffScreen.setAccessibilityDelegate(new View.AccessibilityDelegate() { @Override public void onInitializeAccessibilityEvent(@NonNull View host, @NonNull AccessibilityEvent event) { if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED && isShowing()) { dismiss(); } super.onInitializeAccessibilityEvent(host, event); } }); } } } }
services/tests/servicestests/src/com/android/server/policy/SideFpsEventHandlerTest.java +58 −9 Original line number Original line Diff line number Diff line Loading @@ -31,11 +31,13 @@ import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback; import android.os.Handler; import android.os.Handler; import android.os.PowerManager; import android.os.PowerManager; import android.os.RemoteException; import android.os.test.TestLooper; import android.os.test.TestLooper; import android.testing.AndroidTestingRunner; import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableContext; import android.testing.TestableResources; import android.testing.TestableResources; import android.view.Window; import android.view.Window; import android.view.accessibility.AccessibilityManager; import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest; Loading @@ -48,7 +50,8 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import java.util.List; import java.util.List; Loading @@ -71,10 +74,16 @@ public class SideFpsEventHandlerTest { private static final Integer AUTO_DISMISS_DIALOG = 500; private static final Integer AUTO_DISMISS_DIALOG = 500; @Rule public MockitoRule rule = MockitoJUnit.rule(); @Rule @Rule public TestableContext mContext = public TestableContext mContext = new TestableContext(InstrumentationRegistry.getContext(), null); new TestableContext(InstrumentationRegistry.getContext(), null); private final AccessibilityManager mAccessibilityManager = mContext.getSystemService(AccessibilityManager.class); @Mock @Mock private PackageManager mPackageManager; private PackageManager mPackageManager; @Mock @Mock Loading @@ -89,9 +98,8 @@ public class SideFpsEventHandlerTest { private BiometricStateListener mBiometricStateListener; private BiometricStateListener mBiometricStateListener; @Before @Before public void setup() { public void setup() throws RemoteException { MockitoAnnotations.initMocks(this); disableAccessibility(); mContext.addMockSystemService(PackageManager.class, mPackageManager); mContext.addMockSystemService(PackageManager.class, mPackageManager); mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); mContext.addMockSystemService(FingerprintManager.class, mFingerprintManager); TestableResources resources = mContext.getOrCreateTestableResources(); TestableResources resources = mContext.getOrCreateTestableResources(); Loading Loading @@ -192,9 +200,8 @@ public class SideFpsEventHandlerTest { } } @Test @Test public void dialogDismissesAfterTime() throws Exception { public void dialogDismissesAfterTime_accessibilityDisabled() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); Loading @@ -207,9 +214,23 @@ public class SideFpsEventHandlerTest { } } @Test @Test public void dialogDoesNotDismissOnSensorTouch() throws Exception { public void dialogDoesNotDismissAfterTime_accessibilityEnabled() throws Exception { enableAccessibility(); setupWithSensor(true /* hasSfps */, true /* initialized */); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); mLooper.dispatchAll(); verify(mDialog).show(); mLooper.moveTimeForward(AUTO_DISMISS_DIALOG); mLooper.dispatchAll(); verify(mDialog, never()).dismiss(); } @Test public void dialogDoesNotDismissOnSensorTouch_accessibilityDisabled() throws Exception { setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); Loading @@ -218,12 +239,26 @@ public class SideFpsEventHandlerTest { verify(mDialog).show(); verify(mDialog).show(); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mLooper.moveTimeForward(AUTO_DISMISS_DIALOG - 1); mLooper.dispatchAll(); mLooper.dispatchAll(); verify(mDialog, never()).dismiss(); verify(mDialog, never()).dismiss(); } } @Test public void dialogDismissesOnSensorTouch_accessibilityEnabled() throws Exception { enableAccessibility(); setupWithSensor(true /* hasSfps */, true /* initialized */); setBiometricState(BiometricStateListener.STATE_ENROLLING); when(mDialog.isShowing()).thenReturn(true); assertThat(mEventHandler.shouldConsumeSinglePress(80000L)).isTrue(); mLooper.dispatchAll(); verify(mDialog).show(); mBiometricStateListener.onBiometricAction(BiometricStateListener.ACTION_SENSOR_TOUCH); mLooper.dispatchAll(); verify(mDialog).dismiss(); } private void setBiometricState(@BiometricStateListener.State int newState) { private void setBiometricState(@BiometricStateListener.State int newState) { if (mBiometricStateListener != null) { if (mBiometricStateListener != null) { mBiometricStateListener.onStateChanged(newState); mBiometricStateListener.onStateChanged(newState); Loading @@ -231,6 +266,20 @@ public class SideFpsEventHandlerTest { } } } } private void enableAccessibility() throws RemoteException { if (mAccessibilityManager != null) { mAccessibilityManager.getClient().setState(1); mLooper.dispatchAll(); } } private void disableAccessibility() throws RemoteException { if (mAccessibilityManager != null) { mAccessibilityManager.getClient().setState(0); mLooper.dispatchAll(); } } private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception { private void setupWithSensor(boolean hasSfps, boolean initialized) throws Exception { when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) when(mPackageManager.hasSystemFeature(eq(PackageManager.FEATURE_FINGERPRINT))) .thenReturn(true); .thenReturn(true); Loading