1 /* 2 * Copyright (C) 2015 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.biometrics.fingerprint; 18 19 import android.app.settings.SettingsEnums; 20 import android.content.ComponentName; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.hardware.fingerprint.FingerprintManager; 24 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 25 import android.os.Bundle; 26 import android.text.TextUtils; 27 import android.util.Log; 28 import android.view.View; 29 import android.view.ViewGroup; 30 31 import androidx.annotation.VisibleForTesting; 32 33 import com.android.settings.R; 34 import com.android.settings.Utils; 35 import com.android.settings.biometrics.BiometricEnrollBase; 36 import com.android.settings.biometrics.BiometricUtils; 37 import com.android.settings.biometrics.fingerprint.feature.SfpsRestToUnlockFeature; 38 import com.android.settings.overlay.FeatureFactory; 39 40 import com.google.android.setupcompat.template.FooterBarMixin; 41 import com.google.android.setupcompat.template.FooterButton; 42 import com.google.android.setupcompat.util.WizardManagerHelper; 43 44 import java.util.List; 45 /** 46 * Activity which concludes fingerprint enrollment. 47 */ 48 public class FingerprintEnrollFinish extends BiometricEnrollBase { 49 50 private static final String TAG = "FingerprintEnrollFinish"; 51 private static final String ACTION_FINGERPRINT_SETTINGS = 52 "android.settings.FINGERPRINT_SETTINGS"; 53 @VisibleForTesting 54 public static final String FINGERPRINT_SUGGESTION_ACTIVITY = 55 "com.android.settings.SetupFingerprintSuggestionActivity"; 56 57 private FingerprintManager mFingerprintManager; 58 59 private boolean mCanAssumeSfps; 60 61 private boolean mIsAddAnotherOrFinish; 62 63 private SfpsRestToUnlockFeature mSfpsRestToUnlockFeature; 64 65 @Override onCreate(Bundle savedInstanceState)66 protected void onCreate(Bundle savedInstanceState) { 67 super.onCreate(savedInstanceState); 68 mFingerprintManager = getSystemService(FingerprintManager.class); 69 final List<FingerprintSensorPropertiesInternal> props = 70 mFingerprintManager.getSensorPropertiesInternal(); 71 mCanAssumeSfps = props != null && props.size() == 1 && props.get(0).isAnySidefpsType(); 72 if (mCanAssumeSfps) { 73 mSfpsRestToUnlockFeature = FeatureFactory.getFeatureFactory() 74 .getFingerprintFeatureProvider().getSfpsRestToUnlockFeature(this); 75 setContentView(R.layout.sfps_enroll_finish); 76 setUpRestToUnlockLayout(); 77 } else { 78 setContentView(R.layout.fingerprint_enroll_finish); 79 } 80 setHeaderText(R.string.security_settings_fingerprint_enroll_finish_title); 81 setDescriptionText(Utils.isPrivateProfile(mUserId, getApplicationContext()) 82 ? R.string.private_space_fingerprint_enroll_finish_message 83 : R.string.security_settings_fingerprint_enroll_finish_v2_message); 84 85 final String sfpsDescription = mSfpsRestToUnlockFeature != null 86 ? mSfpsRestToUnlockFeature.getDescriptionForSfps(this) 87 : null; 88 if (mCanAssumeSfps && !TextUtils.isEmpty(sfpsDescription)) { 89 setDescriptionForSfps(sfpsDescription); 90 } 91 92 mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class); 93 mFooterBarMixin.setSecondaryButton( 94 new FooterButton.Builder(this) 95 .setText(R.string.fingerprint_enroll_button_add) 96 .setButtonType(FooterButton.ButtonType.SKIP) 97 .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Secondary) 98 .build() 99 ); 100 101 mFooterBarMixin.setPrimaryButton( 102 new FooterButton.Builder(this) 103 .setText(R.string.security_settings_fingerprint_enroll_done) 104 .setListener(this::onNextButtonClick) 105 .setButtonType(FooterButton.ButtonType.NEXT) 106 .setTheme(com.google.android.setupdesign.R.style.SudGlifButton_Primary) 107 .build() 108 ); 109 } 110 setDescriptionForSfps(String sfpsDescription)111 private void setDescriptionForSfps(String sfpsDescription) { 112 final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this); 113 if (fpm != null) { 114 final List<FingerprintSensorPropertiesInternal> props = 115 fpm.getSensorPropertiesInternal(); 116 final int maxEnrollments = props.get(0).maxEnrollmentsPerUser; 117 final int enrolled = fpm.getEnrolledFingerprints(mUserId).size(); 118 if (enrolled < maxEnrollments) { 119 setDescriptionText(sfpsDescription); 120 } 121 } 122 } 123 setUpRestToUnlockLayout()124 private void setUpRestToUnlockLayout() { 125 final ViewGroup contentFrame = findViewById(R.id.sfps_enrollment_finish_content_frame); 126 final View restToUnlockLayout = mSfpsRestToUnlockFeature.getRestToUnlockLayout(this); 127 if (restToUnlockLayout == null) return; 128 contentFrame.removeAllViews(); 129 contentFrame.addView(restToUnlockLayout); 130 } 131 132 @Override onBackPressed()133 public void onBackPressed() { 134 updateFingerprintSuggestionEnableState(); 135 Intent intent = getIntent().putExtra(EXTRA_FINISHED_ENROLL_FINGERPRINT, true); 136 setResult(RESULT_CANCELED, intent); 137 finish(); 138 } 139 140 @Override onResume()141 protected void onResume() { 142 super.onResume(); 143 FooterButton addButton = mFooterBarMixin.getSecondaryButton(); 144 145 final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this); 146 boolean hideAddAnother = false; 147 if (fpm != null) { 148 final List<FingerprintSensorPropertiesInternal> props = 149 fpm.getSensorPropertiesInternal(); 150 int maxEnrollments = props.get(0).maxEnrollmentsPerUser; 151 int enrolled = fpm.getEnrolledFingerprints(mUserId).size(); 152 hideAddAnother = enrolled >= maxEnrollments; 153 } 154 if (hideAddAnother) { 155 // Don't show "Add" button if too many fingerprints already added 156 addButton.setVisibility(View.INVISIBLE); 157 } else { 158 addButton.setOnClickListener(this::onAddAnotherButtonClick); 159 } 160 } 161 162 @Override onStart()163 protected void onStart() { 164 super.onStart(); 165 166 // Reset it to false every time activity back to fg because this flag is stateless between 167 // different life cycle. 168 mIsAddAnotherOrFinish = false; 169 } 170 171 @Override onNextButtonClick(View view)172 protected void onNextButtonClick(View view) { 173 updateFingerprintSuggestionEnableState(); 174 finishAndToNext(RESULT_FINISHED); 175 } 176 finishAndToNext(int resultCode)177 private void finishAndToNext(int resultCode) { 178 mIsAddAnotherOrFinish = true; 179 setResult(resultCode); 180 if (WizardManagerHelper.isAnySetupWizard(getIntent())) { 181 postEnroll(); 182 } 183 finish(); 184 } 185 updateFingerprintSuggestionEnableState()186 private void updateFingerprintSuggestionEnableState() { 187 final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this); 188 if (fpm != null) { 189 int enrolled = fpm.getEnrolledFingerprints(mUserId).size(); 190 191 // Only show "Add another fingerprint" if the user already enrolled one. 192 // "Add fingerprint" will be shown in the main flow if the user hasn't enrolled any 193 // fingerprints. If the user already added more than one fingerprint, they already know 194 // to add multiple fingerprints so we don't show the suggestion. 195 int flag = (enrolled == 1) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED 196 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED; 197 198 ComponentName componentName = new ComponentName(getApplicationContext(), 199 FINGERPRINT_SUGGESTION_ACTIVITY); 200 getPackageManager().setComponentEnabledSetting( 201 componentName, flag, PackageManager.DONT_KILL_APP); 202 Log.d(TAG, FINGERPRINT_SUGGESTION_ACTIVITY + " enabled state = " + (enrolled == 1)); 203 } 204 } 205 postEnroll()206 private void postEnroll() { 207 final FingerprintManager fpm = Utils.getFingerprintManagerOrNull(this); 208 if (fpm != null) { 209 fpm.revokeChallenge(mUserId, mChallenge); 210 } 211 } 212 onAddAnotherButtonClick(View view)213 private void onAddAnotherButtonClick(View view) { 214 mIsAddAnotherOrFinish = true; 215 startActivityForResult(getFingerprintEnrollingIntent(), BiometricUtils.REQUEST_ADD_ANOTHER); 216 } 217 218 @Override shouldFinishWhenBackgrounded()219 protected boolean shouldFinishWhenBackgrounded() { 220 return !mIsAddAnotherOrFinish && super.shouldFinishWhenBackgrounded(); 221 } 222 223 @Override onActivityResult(int requestCode, int resultCode, Intent data)224 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 225 updateFingerprintSuggestionEnableState(); 226 if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER && resultCode == RESULT_TIMEOUT) { 227 finishAndToNext(resultCode); 228 } else if (requestCode == BiometricUtils.REQUEST_ADD_ANOTHER 229 && resultCode != RESULT_CANCELED) { 230 // If user cancel during "Add another", just use similar flow on "Next" button 231 finishAndToNext(RESULT_FINISHED); 232 } else { 233 super.onActivityResult(requestCode, resultCode, data); 234 } 235 } 236 237 @Override getMetricsCategory()238 public int getMetricsCategory() { 239 return SettingsEnums.FINGERPRINT_ENROLL_FINISH; 240 } 241 } 242