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