• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.face;
18 
19 import android.app.settings.SettingsEnums;
20 import android.content.Intent;
21 import android.hardware.face.FaceManager;
22 import android.os.Bundle;
23 import android.text.TextUtils;
24 import android.util.Log;
25 import android.view.View;
26 import android.view.animation.AnimationUtils;
27 import android.view.animation.Interpolator;
28 import android.widget.TextView;
29 
30 import com.android.settings.R;
31 import com.android.settings.biometrics.BiometricEnrollBase;
32 import com.android.settings.biometrics.BiometricEnrollSidecar;
33 import com.android.settings.biometrics.BiometricErrorDialog;
34 import com.android.settings.biometrics.BiometricUtils;
35 import com.android.settings.biometrics.BiometricsEnrollEnrolling;
36 import com.android.settings.slices.CustomSliceRegistry;
37 
38 import com.google.android.setupcompat.template.FooterBarMixin;
39 import com.google.android.setupcompat.template.FooterButton;
40 import com.google.android.setupcompat.util.WizardManagerHelper;
41 
42 import java.util.ArrayList;
43 
44 public class FaceEnrollEnrolling extends BiometricsEnrollEnrolling {
45 
46     private static final String TAG = "FaceEnrollEnrolling";
47     private static final boolean DEBUG = false;
48     private static final String TAG_FACE_PREVIEW = "tag_preview";
49 
50     private TextView mErrorText;
51     private Interpolator mLinearOutSlowInInterpolator;
52     private FaceEnrollPreviewFragment mPreviewFragment;
53 
54     private ArrayList<Integer> mDisabledFeatures = new ArrayList<>();
55     private ParticleCollection.Listener mListener = new ParticleCollection.Listener() {
56         @Override
57         public void onEnrolled() {
58             FaceEnrollEnrolling.this.launchFinish(mToken);
59         }
60     };
61 
62     public static class FaceErrorDialog extends BiometricErrorDialog {
newInstance(CharSequence msg, int msgId)63         static FaceErrorDialog newInstance(CharSequence msg, int msgId) {
64             FaceErrorDialog dialog = new FaceErrorDialog();
65             Bundle args = new Bundle();
66             args.putCharSequence(KEY_ERROR_MSG, msg);
67             args.putInt(KEY_ERROR_ID, msgId);
68             dialog.setArguments(args);
69             return dialog;
70         }
71 
72         @Override
getMetricsCategory()73         public int getMetricsCategory() {
74             return SettingsEnums.DIALOG_FACE_ERROR;
75         }
76 
77         @Override
getTitleResId()78         public int getTitleResId() {
79             return R.string.security_settings_face_enroll_error_dialog_title;
80         }
81 
82         @Override
getOkButtonTextResId()83         public int getOkButtonTextResId() {
84             return R.string.security_settings_face_enroll_dialog_ok;
85         }
86     }
87 
88     @Override
onCreate(Bundle savedInstanceState)89     protected void onCreate(Bundle savedInstanceState) {
90         super.onCreate(savedInstanceState);
91         setContentView(R.layout.face_enroll_enrolling);
92         setHeaderText(R.string.security_settings_face_enroll_repeat_title);
93         mErrorText = findViewById(R.id.error_text);
94         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(
95                 this, android.R.interpolator.linear_out_slow_in);
96 
97         mFooterBarMixin = getLayout().getMixin(FooterBarMixin.class);
98         mFooterBarMixin.setSecondaryButton(
99                 new FooterButton.Builder(this)
100                         .setText(R.string.security_settings_face_enroll_enrolling_skip)
101                         .setListener(this::onSkipButtonClick)
102                         .setButtonType(FooterButton.ButtonType.SKIP)
103                         .setTheme(R.style.SudGlifButton_Secondary)
104                         .build()
105         );
106 
107         if (!getIntent().getBooleanExtra(BiometricEnrollBase.EXTRA_KEY_REQUIRE_DIVERSITY, true)) {
108             mDisabledFeatures.add(FaceManager.FEATURE_REQUIRE_REQUIRE_DIVERSITY);
109         }
110         if (!getIntent().getBooleanExtra(BiometricEnrollBase.EXTRA_KEY_REQUIRE_VISION, true)) {
111             mDisabledFeatures.add(FaceManager.FEATURE_REQUIRE_ATTENTION);
112         }
113 
114         startEnrollment();
115     }
116 
117     @Override
onStop()118     protected void onStop() {
119         if (!isChangingConfigurations()) {
120             if (!WizardManagerHelper.isAnySetupWizard(getIntent())
121                     && !BiometricUtils.isAnyMultiBiometricFlow(this)) {
122                 setResult(RESULT_TIMEOUT);
123             }
124             finish();
125         }
126 
127         super.onStop();
128     }
129 
130     @Override
shouldFinishWhenBackgrounded()131     protected boolean shouldFinishWhenBackgrounded() {
132         // Prevent super.onStop() from finishing, since we handle this in our onStop().
133         return false;
134     }
135 
136     @Override
startEnrollment()137     public void startEnrollment() {
138         super.startEnrollment();
139         mPreviewFragment = (FaceEnrollPreviewFragment) getSupportFragmentManager()
140                 .findFragmentByTag(TAG_FACE_PREVIEW);
141         if (mPreviewFragment == null) {
142             mPreviewFragment = new FaceEnrollPreviewFragment();
143             getSupportFragmentManager().beginTransaction().add(mPreviewFragment, TAG_FACE_PREVIEW)
144                     .commitAllowingStateLoss();
145         }
146         mPreviewFragment.setListener(mListener);
147     }
148 
149     @Override
getFinishIntent()150     protected Intent getFinishIntent() {
151         return new Intent(this, FaceEnrollFinish.class);
152     }
153 
154     @Override
getSidecar()155     protected BiometricEnrollSidecar getSidecar() {
156         final int[] disabledFeatures = new int[mDisabledFeatures.size()];
157         for (int i = 0; i < mDisabledFeatures.size(); i++) {
158             disabledFeatures[i] = mDisabledFeatures.get(i);
159         }
160 
161         return new FaceEnrollSidecar(disabledFeatures);
162     }
163 
164     @Override
shouldStartAutomatically()165     protected boolean shouldStartAutomatically() {
166         return false;
167     }
168 
169     @Override
getMetricsCategory()170     public int getMetricsCategory() {
171         return SettingsEnums.FACE_ENROLL_ENROLLING;
172     }
173 
174     @Override
onEnrollmentHelp(int helpMsgId, CharSequence helpString)175     public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
176         if (!TextUtils.isEmpty(helpString)) {
177             showError(helpString);
178         }
179         mPreviewFragment.onEnrollmentHelp(helpMsgId, helpString);
180     }
181 
182     @Override
onEnrollmentError(int errMsgId, CharSequence errString)183     public void onEnrollmentError(int errMsgId, CharSequence errString) {
184         int msgId;
185         switch (errMsgId) {
186             case FaceManager.FACE_ERROR_TIMEOUT:
187                 msgId = R.string.security_settings_face_enroll_error_timeout_dialog_message;
188                 break;
189             default:
190                 msgId = R.string.security_settings_face_enroll_error_generic_dialog_message;
191                 break;
192         }
193         mPreviewFragment.onEnrollmentError(errMsgId, errString);
194         showErrorDialog(getText(msgId), errMsgId);
195     }
196 
197     @Override
onEnrollmentProgressChange(int steps, int remaining)198     public void onEnrollmentProgressChange(int steps, int remaining) {
199         if (DEBUG) {
200             Log.v(TAG, "Steps: " + steps + " Remaining: " + remaining);
201         }
202         mPreviewFragment.onEnrollmentProgressChange(steps, remaining);
203 
204         // TODO: Update the actual animation
205         showError("Steps: " + steps + " Remaining: " + remaining);
206 
207         // TODO: Have this match any animations that UX comes up with
208         if (remaining == 0) {
209             // Force the reload of the FaceEnroll slice in case a user has enrolled,
210             // this will cause the slice to no longer appear.
211             getApplicationContext().getContentResolver().notifyChange(
212                     CustomSliceRegistry.FACE_ENROLL_SLICE_URI, null);
213             launchFinish(mToken);
214         }
215     }
216 
showErrorDialog(CharSequence msg, int msgId)217     private void showErrorDialog(CharSequence msg, int msgId) {
218         BiometricErrorDialog dialog = FaceErrorDialog.newInstance(msg, msgId);
219         dialog.show(getSupportFragmentManager(), FaceErrorDialog.class.getName());
220     }
221 
showError(CharSequence error)222     private void showError(CharSequence error) {
223         mErrorText.setText(error);
224         if (mErrorText.getVisibility() == View.INVISIBLE) {
225             mErrorText.setVisibility(View.VISIBLE);
226             mErrorText.setTranslationY(getResources().getDimensionPixelSize(
227                     R.dimen.fingerprint_error_text_appear_distance));
228             mErrorText.setAlpha(0f);
229             mErrorText.animate()
230                     .alpha(1f)
231                     .translationY(0f)
232                     .setDuration(200)
233                     .setInterpolator(mLinearOutSlowInInterpolator)
234                     .start();
235         } else {
236             mErrorText.animate().cancel();
237             mErrorText.setAlpha(1f);
238             mErrorText.setTranslationY(0f);
239         }
240     }
241 }
242