1 /* 2 * Copyright (C) 2017 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.settings.fingerprint; 18 19 import static com.google.common.truth.Truth.assertThat; 20 import static org.mockito.Matchers.any; 21 import static org.mockito.Matchers.anyInt; 22 import static org.mockito.Mockito.verify; 23 import static org.robolectric.RuntimeEnvironment.application; 24 25 import android.content.ComponentName; 26 import android.content.Intent; 27 import android.hardware.fingerprint.FingerprintManager; 28 import android.hardware.fingerprint.FingerprintManager.EnrollmentCallback; 29 import android.os.CancellationSignal; 30 import android.widget.Button; 31 32 import com.android.settings.R; 33 import com.android.settings.password.ChooseLockSettingsHelper; 34 import com.android.settings.testutils.FakeFeatureFactory; 35 import com.android.settings.testutils.SettingsRobolectricTestRunner; 36 import com.android.settings.testutils.shadow.SettingsShadowResources; 37 import com.android.settings.testutils.shadow.ShadowUtils; 38 39 import org.junit.After; 40 import org.junit.Before; 41 import org.junit.Test; 42 import org.junit.runner.RunWith; 43 import org.mockito.ArgumentCaptor; 44 import org.mockito.Mock; 45 import org.mockito.MockitoAnnotations; 46 import org.robolectric.Robolectric; 47 import org.robolectric.Shadows; 48 import org.robolectric.annotation.Config; 49 import org.robolectric.shadows.ShadowActivity; 50 import org.robolectric.shadows.ShadowActivity.IntentForResult; 51 52 @RunWith(SettingsRobolectricTestRunner.class) 53 @Config(shadows = {SettingsShadowResources.SettingsShadowTheme.class, ShadowUtils.class}) 54 public class FingerprintEnrollFindSensorTest { 55 56 @Mock 57 private FingerprintManager mFingerprintManager; 58 59 private FingerprintEnrollFindSensor mActivity; 60 61 @Before 62 public void setUp() { 63 MockitoAnnotations.initMocks(this); 64 ShadowUtils.setFingerprintManager(mFingerprintManager); 65 FakeFeatureFactory.setupForTest(); 66 67 mActivity = Robolectric.buildActivity( 68 FingerprintEnrollFindSensor.class, 69 new Intent() 70 // Set the challenge token so the confirm screen will not be shown 71 .putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, new byte[0])) 72 .setup().get(); 73 } 74 75 @After 76 public void tearDown() { 77 ShadowUtils.reset(); 78 } 79 80 @Test 81 public void enrollFingerprint_shouldProceed() { 82 EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback(); 83 84 enrollmentCallback.onEnrollmentProgress(123); 85 enrollmentCallback.onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, "test"); 86 87 ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); 88 IntentForResult startedActivity = 89 shadowActivity.getNextStartedActivityForResult(); 90 assertThat(startedActivity).named("Next activity 1").isNotNull(); 91 assertThat(startedActivity.intent.getComponent()) 92 .isEqualTo(new ComponentName(application, FingerprintEnrollEnrolling.class)); 93 } 94 95 @Test 96 public void enrollFingerprintTwice_shouldStartOneEnrolling() { 97 EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback(); 98 99 enrollmentCallback.onEnrollmentProgress(123); 100 enrollmentCallback.onEnrollmentProgress(123); // A second enroll should be a no-op 101 102 ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); 103 IntentForResult startedActivity = 104 shadowActivity.getNextStartedActivityForResult(); 105 assertThat(startedActivity).named("Next activity 1").isNotNull(); 106 assertThat(startedActivity.intent.getComponent()) 107 .isEqualTo(new ComponentName(application, FingerprintEnrollEnrolling.class)); 108 109 // Should only start one next activity 110 assertThat(shadowActivity.getNextStartedActivityForResult()).named("Next activity 2") 111 .isNull(); 112 } 113 114 // Use a non-default resource qualifier to load the test layout in 115 // robotests/res/layout-mcc999/fingerprint_enroll_find_sensor. This layout is a copy of the 116 // regular find sensor layout, with the animation removed. 117 @Config(qualifiers = "mcc999") 118 @Test 119 public void layoutWithoutAnimation_shouldNotCrash() { 120 EnrollmentCallback enrollmentCallback = verifyAndCaptureEnrollmentCallback(); 121 enrollmentCallback.onEnrollmentProgress(123); 122 enrollmentCallback.onEnrollmentError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, "test"); 123 124 ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); 125 IntentForResult startedActivity = 126 shadowActivity.getNextStartedActivityForResult(); 127 assertThat(startedActivity).named("Next activity").isNotNull(); 128 assertThat(startedActivity.intent.getComponent()) 129 .isEqualTo(new ComponentName(application, FingerprintEnrollEnrolling.class)); 130 } 131 132 @Test 133 public void clickSkip_shouldReturnResultSkip() { 134 Button skipButton = mActivity.findViewById(R.id.skip_button); 135 skipButton.performClick(); 136 137 ShadowActivity shadowActivity = Shadows.shadowOf(mActivity); 138 assertThat(shadowActivity.getResultCode()).named("result code") 139 .isEqualTo(FingerprintEnrollBase.RESULT_SKIP); 140 } 141 142 private EnrollmentCallback verifyAndCaptureEnrollmentCallback() { 143 ArgumentCaptor<EnrollmentCallback> callbackCaptor = 144 ArgumentCaptor.forClass(EnrollmentCallback.class); 145 verify(mFingerprintManager).enroll( 146 any(byte[].class), 147 any(CancellationSignal.class), 148 anyInt(), 149 anyInt(), 150 callbackCaptor.capture()); 151 152 return callbackCaptor.getValue(); 153 } 154 } 155