• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.biometrics2.ui.view;
18 
19 import static androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult;
20 import static androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.APPLICATION_KEY;
21 
22 import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.CHALLENGE_GENERATOR_KEY;
23 import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.ENROLLMENT_REQUEST_KEY;
24 import static com.android.settings.biometrics2.factory.BiometricsViewModelFactory.USER_ID_KEY;
25 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK;
26 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK;
27 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_IS_GENERATING_CHALLENGE;
28 import static com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.CREDENTIAL_VALID;
29 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.ErrorDialogData;
30 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE;
31 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG;
32 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED;
33 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP;
34 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH;
35 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT;
36 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintEnrollEnrollingAction;
37 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel.FingerprintErrorDialogAction;
38 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG;
39 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP;
40 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START;
41 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel.FingerprintEnrollFindSensorAction;
42 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK;
43 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK;
44 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel.FingerprintEnrollFinishAction;
45 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
46 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH;
47 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
48 import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FingerprintEnrollIntroAction;
49 
50 import android.annotation.StyleRes;
51 import android.app.Application;
52 import android.content.Intent;
53 import android.content.res.ColorStateList;
54 import android.content.res.Configuration;
55 import android.content.res.Resources;
56 import android.graphics.Color;
57 import android.os.Bundle;
58 import android.os.SystemClock;
59 import android.util.Log;
60 
61 import androidx.activity.result.ActivityResult;
62 import androidx.activity.result.ActivityResultCallback;
63 import androidx.activity.result.ActivityResultLauncher;
64 import androidx.annotation.ColorInt;
65 import androidx.annotation.NonNull;
66 import androidx.annotation.Nullable;
67 import androidx.fragment.app.Fragment;
68 import androidx.fragment.app.FragmentActivity;
69 import androidx.lifecycle.Observer;
70 import androidx.lifecycle.ViewModelProvider;
71 import androidx.lifecycle.viewmodel.CreationExtras;
72 import androidx.lifecycle.viewmodel.MutableCreationExtras;
73 
74 import com.android.settings.R;
75 import com.android.settings.Utils;
76 import com.android.settings.biometrics.BiometricEnrollBase;
77 import com.android.settings.biometrics2.data.repository.FingerprintRepository;
78 import com.android.settings.biometrics2.factory.BiometricsViewModelFactory;
79 import com.android.settings.biometrics2.ui.model.CredentialModel;
80 import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
81 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel;
82 import com.android.settings.biometrics2.ui.viewmodel.AutoCredentialViewModel.FingerprintChallengeGenerator;
83 import com.android.settings.biometrics2.ui.viewmodel.DeviceFoldedViewModel;
84 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollEnrollingViewModel;
85 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFindSensorViewModel;
86 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollFinishViewModel;
87 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel;
88 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollProgressViewModel;
89 import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollmentViewModel;
90 import com.android.settings.overlay.FeatureFactory;
91 
92 import com.google.android.setupdesign.util.ThemeHelper;
93 
94 /**
95  * Fingerprint enrollment activity implementation
96  */
97 public class FingerprintEnrollmentActivity extends FragmentActivity {
98 
99     private static final boolean DEBUG = false;
100     private static final String TAG = "FingerprintEnrollmentActivity";
101 
102     private static final String INTRO_TAG = "intro";
103     private static final String FIND_UDFPS_TAG = "find-udfps";
104     private static final String FIND_SFPS_TAG = "find-sfps";
105     private static final String FIND_RFPS_TAG = "find-rfps";
106     private static final String ENROLLING_UDFPS_TAG = "enrolling-udfps";
107     private static final String ENROLLING_SFPS_TAG = "enrolling-sfps";
108     private static final String ENROLLING_RFPS_TAG = "enrolling-rfps";
109     private static final String FINISH_TAG = "finish";
110     private static final String SKIP_SETUP_FIND_FPS_DIALOG_TAG = "skip-setup-dialog";
111     private static final String ENROLLING_ERROR_DIALOG_TAG = "enrolling-error-dialog";
112 
113     protected static final int LAUNCH_CONFIRM_LOCK_ACTIVITY = 1;
114 
115     // This flag is used for addBackStack(), we do not save it in ViewModel because it is just used
116     // during FragmentManager calls
117     private boolean mIsFirstFragmentAdded = false;
118 
119     private ViewModelProvider mViewModelProvider;
120     private FingerprintEnrollmentViewModel mViewModel;
121     private AutoCredentialViewModel mAutoCredentialViewModel;
122     private final Observer<Integer> mIntroActionObserver = action -> {
123         if (DEBUG) {
124             Log.d(TAG, "mIntroActionObserver(" + action + ")");
125         }
126         if (action != null) {
127             onIntroAction(action);
128         }
129     };
130     private final Observer<Integer> mFindSensorActionObserver = action -> {
131         if (DEBUG) {
132             Log.d(TAG, "mFindSensorActionObserver(" + action + ")");
133         }
134         if (action != null) {
135             onFindSensorAction(action);
136         }
137     };
138     private final Observer<Integer> mEnrollingActionObserver = action -> {
139         if (DEBUG) {
140             Log.d(TAG, "mEnrollingActionObserver(" + action + ")");
141         }
142         if (action != null) {
143             onEnrollingAction(action);
144         }
145     };
146     private final Observer<ErrorDialogData> mEnrollingErrorDialogObserver = data -> {
147         if (DEBUG) {
148             Log.d(TAG, "mEnrollingErrorDialogObserver(" + data + ")");
149         }
150         if (data != null) {
151             new FingerprintEnrollEnrollingErrorDialog().show(getSupportFragmentManager(),
152                     ENROLLING_ERROR_DIALOG_TAG);
153         }
154     };
155     private final Observer<Integer> mEnrollingErrorDialogActionObserver = action -> {
156         if (DEBUG) {
157             Log.d(TAG, "mEnrollingErrorDialogActionObserver(" + action + ")");
158         }
159         if (action != null) {
160             onEnrollingErrorDialogAction(action);
161         }
162     };
163     private final Observer<Integer> mFinishActionObserver = action -> {
164         if (DEBUG) {
165             Log.d(TAG, "mFinishActionObserver(" + action + ")");
166         }
167         if (action != null) {
168             onFinishAction(action);
169         }
170     };
171     private final ActivityResultCallback<ActivityResult> mChooseLockResultCallback =
172             result -> onChooseOrConfirmLockResult(true /* isChooseLock */, result);
173     private final ActivityResultLauncher<Intent> mChooseLockLauncher =
174             registerForActivityResult(new StartActivityForResult(), mChooseLockResultCallback);
175 
176     @Override
onCreate(@ullable Bundle savedInstanceState)177     protected void onCreate(@Nullable Bundle savedInstanceState) {
178         super.onCreate(savedInstanceState);
179 
180         mViewModelProvider = new ViewModelProvider(this);
181 
182         mViewModel = mViewModelProvider.get(FingerprintEnrollmentViewModel.class);
183         mViewModel.setSavedInstanceState(savedInstanceState);
184 
185         mAutoCredentialViewModel = mViewModelProvider.get(AutoCredentialViewModel.class);
186         mAutoCredentialViewModel.setCredentialModel(savedInstanceState, getIntent());
187 
188         // Theme
189         setTheme(mViewModel.getRequest().getTheme());
190         ThemeHelper.trySetDynamicColor(this);
191         getWindow().setStatusBarColor(android.graphics.Color.TRANSPARENT);
192 
193         // fragment
194         setContentView(R.layout.biometric_enrollment_container);
195 
196         final Fragment fragment = getSupportFragmentManager().findFragmentById(
197                 R.id.fragment_container_view);
198         if (DEBUG) {
199             Log.d(TAG, "onCreate() has savedInstance:" + (savedInstanceState != null)
200                     + ", fragment:" + fragment);
201         }
202         if (fragment == null) {
203             checkCredential();
204             final EnrollmentRequest request = mViewModel.getRequest();
205             if (request.isSkipFindSensor()) {
206                 startEnrollingFragment();
207             } else if (request.isSkipIntro()) {
208                 startFindSensorFragment();
209             } else {
210                 startIntroFragment();
211             }
212         } else {
213             final String tag = fragment.getTag();
214             if (INTRO_TAG.equals(tag)) {
215                 attachIntroViewModel();
216             } else if (FIND_UDFPS_TAG.equals(tag) || FIND_SFPS_TAG.equals(tag)
217                     || FIND_RFPS_TAG.equals(tag)) {
218                 attachFindSensorViewModel();
219                 attachIntroViewModel();
220             } else if (ENROLLING_UDFPS_TAG.equals(tag) || ENROLLING_SFPS_TAG.equals(tag)
221                     || ENROLLING_RFPS_TAG.equals(tag)) {
222                 attachEnrollingViewModel();
223                 attachFindSensorViewModel();
224                 attachIntroViewModel();
225             } else if (FINISH_TAG.equals(tag)) {
226                 attachFinishViewModel();
227                 attachFindSensorViewModel();
228                 attachIntroViewModel();
229             } else {
230                 Log.e(TAG, "fragment tag " + tag + " not found");
231                 finish();
232                 return;
233             }
234         }
235 
236         // observe LiveData
237         mViewModel.getSetResultLiveData().observe(this, this::onSetActivityResult);
238 
239         mAutoCredentialViewModel.getGenerateChallengeFailedLiveData().observe(this,
240                 this::onGenerateChallengeFailed);
241     }
242 
startFragment(@onNull Class<? extends Fragment> fragmentClass, @NonNull String tag)243     private void startFragment(@NonNull Class<? extends Fragment> fragmentClass,
244             @NonNull String tag) {
245         if (!mIsFirstFragmentAdded) {
246             getSupportFragmentManager().beginTransaction()
247                     .setReorderingAllowed(true)
248                     .replace(R.id.fragment_container_view, fragmentClass, null, tag)
249                     .commit();
250             mIsFirstFragmentAdded = true;
251         } else {
252             getSupportFragmentManager().beginTransaction()
253                     .setReorderingAllowed(true)
254                     .setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
255                             R.anim.shared_x_axis_activity_open_exit,
256                             R.anim.shared_x_axis_activity_close_enter_dynamic_color,
257                             R.anim.shared_x_axis_activity_close_exit)
258                     .replace(R.id.fragment_container_view, fragmentClass, null, tag)
259                     .addToBackStack(tag)
260                     .commit();
261         }
262     }
263 
startIntroFragment()264     private void startIntroFragment() {
265         attachIntroViewModel();
266         startFragment(FingerprintEnrollIntroFragment.class, INTRO_TAG);
267     }
268 
attachIntroViewModel()269     private void attachIntroViewModel() {
270         final EnrollmentRequest request = mViewModel.getRequest();
271         if (request.isSkipIntro() || request.isSkipFindSensor()) {
272             return;
273         }
274 
275         final FingerprintEnrollIntroViewModel introViewModel =
276                 mViewModelProvider.get(FingerprintEnrollIntroViewModel.class);
277 
278         // Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
279         // recreate, like press 'Agree' then press 'back' in FingerprintEnrollFindSensor activity.
280         introViewModel.clearActionLiveData();
281         introViewModel.getActionLiveData().observe(this, mIntroActionObserver);
282     }
283 
284     // We need to make sure token is valid before entering find sensor page
startFindSensorFragment()285     private void startFindSensorFragment() {
286         // Always setToken into progressViewModel even it is not necessary action for UDFPS
287         mViewModelProvider.get(FingerprintEnrollProgressViewModel.class)
288                 .setToken(mAutoCredentialViewModel.getToken());
289 
290         attachFindSensorViewModel();
291 
292         final String tag;
293         final Class<? extends Fragment> fragmentClass;
294         if (mViewModel.canAssumeUdfps()) {
295             tag = FIND_UDFPS_TAG;
296             fragmentClass = FingerprintEnrollFindUdfpsFragment.class;
297         } else if (mViewModel.canAssumeSfps()) {
298             tag = FIND_SFPS_TAG;
299             fragmentClass = FingerprintEnrollFindSfpsFragment.class;
300         } else {
301             tag = FIND_RFPS_TAG;
302             fragmentClass = FingerprintEnrollFindRfpsFragment.class;
303         }
304         startFragment(fragmentClass, tag);
305     }
306 
attachFindSensorViewModel()307     private void attachFindSensorViewModel() {
308         if (mViewModel.getRequest().isSkipFindSensor()) {
309             return;
310         }
311 
312         final FingerprintEnrollFindSensorViewModel findSensorViewModel =
313                 mViewModelProvider.get(FingerprintEnrollFindSensorViewModel.class);
314 
315         // Clear ActionLiveData in FragmentViewModel to prevent getting previous action during
316         // recreate, like press 'Start' then press 'back' in FingerprintEnrollEnrolling activity.
317         findSensorViewModel.clearActionLiveData();
318         findSensorViewModel.getActionLiveData().observe(this, mFindSensorActionObserver);
319     }
320 
startEnrollingFragment()321     private void startEnrollingFragment() {
322         // Always setToken into progressViewModel even it is not necessary action for SFPS or RFPS
323         mViewModelProvider.get(FingerprintEnrollProgressViewModel.class)
324                 .setToken(mAutoCredentialViewModel.getToken());
325 
326         attachEnrollingViewModel();
327 
328         final String tag;
329         final Class<? extends Fragment> fragmentClass;
330         if (mViewModel.canAssumeUdfps()) {
331             tag = ENROLLING_UDFPS_TAG;
332             fragmentClass = FingerprintEnrollEnrollingUdfpsFragment.class;
333         } else if (mViewModel.canAssumeSfps()) {
334             tag = ENROLLING_SFPS_TAG;
335             fragmentClass = FingerprintEnrollEnrollingSfpsFragment.class;
336         } else {
337             tag = ENROLLING_RFPS_TAG;
338             fragmentClass = FingerprintEnrollEnrollingRfpsFragment.class;
339         }
340         startFragment(fragmentClass, tag);
341     }
342 
attachEnrollingViewModel()343     private void attachEnrollingViewModel() {
344         final FingerprintEnrollEnrollingViewModel enrollingViewModel =
345                 mViewModelProvider.get(FingerprintEnrollEnrollingViewModel.class);
346         enrollingViewModel.clearActionLiveData();
347         enrollingViewModel.getActionLiveData().observe(this, mEnrollingActionObserver);
348         enrollingViewModel.getErrorDialogLiveData().observe(this, mEnrollingErrorDialogObserver);
349         enrollingViewModel.getErrorDialogActionLiveData().observe(this,
350                 mEnrollingErrorDialogActionObserver);
351     }
352 
startFinishFragment()353     private void startFinishFragment() {
354         mViewModel.setIsNewFingerprintAdded();
355         attachFinishViewModel();
356 
357         getSupportFragmentManager().popBackStack();
358         if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
359             // Replace enrolling page
360             getSupportFragmentManager().beginTransaction()
361                     .setReorderingAllowed(true)
362                     .setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
363                             R.anim.shared_x_axis_activity_open_exit,
364                             R.anim.shared_x_axis_activity_close_enter_dynamic_color,
365                             R.anim.shared_x_axis_activity_close_exit)
366                     .replace(R.id.fragment_container_view, FingerprintEnrollFinishFragment.class,
367                             null, FINISH_TAG)
368                     .commit();
369         } else {
370             // Remove Enrolling page from backstack, and add Finish page. Latest backstack will
371             // be changed from Intro->FindSensor->Enrolling to Intro->FindSensor->Finish
372             getSupportFragmentManager().beginTransaction()
373                     .setReorderingAllowed(true)
374                     .setCustomAnimations(R.anim.shared_x_axis_activity_open_enter_dynamic_color,
375                             R.anim.shared_x_axis_activity_open_exit,
376                             R.anim.shared_x_axis_activity_close_enter_dynamic_color,
377                             R.anim.shared_x_axis_activity_close_exit)
378                     .replace(R.id.fragment_container_view, FingerprintEnrollFinishFragment.class,
379                             null, FINISH_TAG)
380                     .addToBackStack(FINISH_TAG)
381                     .commit();
382         }
383     }
384 
attachFinishViewModel()385     private void attachFinishViewModel() {
386         final FingerprintEnrollFinishViewModel viewModel =
387                 mViewModelProvider.get(FingerprintEnrollFinishViewModel.class);
388         viewModel.clearActionLiveData();
389         viewModel.getActionLiveData().observe(this, mFinishActionObserver);
390     }
391 
onGenerateChallengeFailed(@onNull Boolean ignoredBoolean)392     private void onGenerateChallengeFailed(@NonNull Boolean ignoredBoolean) {
393         onSetActivityResult(new ActivityResult(RESULT_CANCELED, null));
394     }
395 
onSetActivityResult(@onNull ActivityResult result)396     private void onSetActivityResult(@NonNull ActivityResult result) {
397         final Bundle challengeExtras = mAutoCredentialViewModel.createGeneratingChallengeExtras();
398         final ActivityResult overrideResult = mViewModel.getOverrideActivityResult(
399                 result, challengeExtras);
400         if (DEBUG) {
401             Log.d(TAG, "onSetActivityResult(" + result + "), override:" + overrideResult
402                     + ") challengeExtras:" + challengeExtras);
403         }
404         setResult(overrideResult.getResultCode(), overrideResult.getData());
405         finish();
406     }
407 
checkCredential()408     private void checkCredential() {
409         switch (mAutoCredentialViewModel.checkCredential()) {
410             case CREDENTIAL_FAIL_NEED_TO_CHOOSE_LOCK: {
411                 final Intent intent = mAutoCredentialViewModel.createChooseLockIntent(this,
412                         mViewModel.getRequest().isSuw(), mViewModel.getRequest().getSuwExtras());
413                 if (!mViewModel.isWaitingActivityResult().compareAndSet(false, true)) {
414                     Log.w(TAG, "chooseLock, fail to set isWaiting flag to true");
415                 }
416                 mChooseLockLauncher.launch(intent);
417                 return;
418             }
419             case CREDENTIAL_FAIL_NEED_TO_CONFIRM_LOCK: {
420                 final boolean launched = mAutoCredentialViewModel.createConfirmLockLauncher(
421                         this,
422                         LAUNCH_CONFIRM_LOCK_ACTIVITY,
423                         getString(R.string.security_settings_fingerprint_preference_title)
424                 ).launch();
425                 if (!launched) {
426                     // This shouldn't happen, as we should only end up at this step if a lock thingy
427                     // is already set.
428                     Log.e(TAG, "confirmLock, launched is true");
429                     finish();
430                 } else if (!mViewModel.isWaitingActivityResult().compareAndSet(false, true)) {
431                     Log.w(TAG, "confirmLock, fail to set isWaiting flag to true");
432                 }
433                 return;
434             }
435             case CREDENTIAL_VALID:
436             case CREDENTIAL_IS_GENERATING_CHALLENGE: {
437                 // Do nothing
438             }
439         }
440     }
441 
onChooseOrConfirmLockResult(boolean isChooseLock, @NonNull ActivityResult activityResult)442     private void onChooseOrConfirmLockResult(boolean isChooseLock,
443             @NonNull ActivityResult activityResult) {
444         if (!mViewModel.isWaitingActivityResult().compareAndSet(true, false)) {
445             Log.w(TAG, "isChooseLock:" + isChooseLock + ", fail to unset waiting flag");
446         }
447         if (mAutoCredentialViewModel.checkNewCredentialFromActivityResult(
448                 isChooseLock, activityResult)) {
449             overridePendingTransition(R.anim.sud_slide_next_in, R.anim.sud_slide_next_out);
450         } else {
451             onSetActivityResult(activityResult);
452         }
453     }
454 
onIntroAction(@ingerprintEnrollIntroAction int action)455     private void onIntroAction(@FingerprintEnrollIntroAction int action) {
456         switch (action) {
457             case FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH: {
458                 onSetActivityResult(
459                         new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null));
460                 return;
461             }
462             case FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL: {
463                 onSetActivityResult(
464                         new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
465                 return;
466             }
467             case FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL: {
468                 startFindSensorFragment();
469             }
470         }
471     }
472 
onFindSensorAction(@ingerprintEnrollFindSensorAction int action)473     private void onFindSensorAction(@FingerprintEnrollFindSensorAction int action) {
474         switch (action) {
475             case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_SKIP: {
476                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
477                 return;
478             }
479             case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_DIALOG: {
480                 new SkipSetupFindFpsDialog().show(getSupportFragmentManager(),
481                         SKIP_SETUP_FIND_FPS_DIALOG_TAG);
482                 return;
483             }
484             case FINGERPRINT_ENROLL_FIND_SENSOR_ACTION_START: {
485                 startEnrollingFragment();
486             }
487         }
488     }
489 
onEnrollingAction(@ingerprintEnrollEnrollingAction int action)490     private void onEnrollingAction(@FingerprintEnrollEnrollingAction int action) {
491         switch (action) {
492             case FINGERPRINT_ENROLL_ENROLLING_ACTION_DONE: {
493                 startFinishFragment();
494                 break;
495             }
496             case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_USER_SKIP: {
497                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_SKIP, null));
498                 break;
499             }
500             case FINGERPRINT_ENROLL_ENROLLING_ACTION_SHOW_ICON_TOUCH_DIALOG: {
501                 new FingerprintEnrollEnrollingIconTouchDialog().show(getSupportFragmentManager(),
502                         SKIP_SETUP_FIND_FPS_DIALOG_TAG);
503                 break;
504             }
505             case FINGERPRINT_ENROLL_ENROLLING_CANCELED_BECAUSE_BACK_PRESSED: {
506                 if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
507                     getSupportFragmentManager().popBackStack();
508                 } else {
509                     onSetActivityResult(new ActivityResult(RESULT_CANCELED, null));
510                 }
511                 break;
512             }
513         }
514     }
515 
onEnrollingErrorDialogAction(@ingerprintErrorDialogAction int action)516     private void onEnrollingErrorDialogAction(@FingerprintErrorDialogAction int action) {
517         switch (action) {
518             case FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_FINISH:
519                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, null));
520                 break;
521             case FINGERPRINT_ERROR_DIALOG_ACTION_SET_RESULT_TIMEOUT:
522                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_TIMEOUT, null));
523                 break;
524         }
525     }
526 
onFinishAction(@ingerprintEnrollFinishAction int action)527     private void onFinishAction(@FingerprintEnrollFinishAction int action) {
528         switch (action) {
529             case FINGERPRINT_ENROLL_FINISH_ACTION_ADD_BUTTON_CLICK: {
530                 startEnrollingFragment();
531                 break;
532             }
533             case FINGERPRINT_ENROLL_FINISH_ACTION_NEXT_BUTTON_CLICK: {
534                 final Intent data;
535                 if (mViewModel.getRequest().isSuw()) {
536                     data = new Intent();
537                     data.putExtras(mViewModel.getSuwFingerprintCountExtra(
538                             mAutoCredentialViewModel.getUserId()));
539                 } else {
540                     data = null;
541                 }
542                 onSetActivityResult(new ActivityResult(BiometricEnrollBase.RESULT_FINISHED, data));
543                 break;
544             }
545         }
546     }
547 
548     @Override
onPause()549     protected void onPause() {
550         super.onPause();
551         mViewModel.checkFinishActivityDuringOnPause(isFinishing(), isChangingConfigurations());
552     }
553 
554     @Override
onDestroy()555     protected void onDestroy() {
556         mViewModel.updateFingerprintSuggestionEnableState(mAutoCredentialViewModel.getUserId());
557         super.onDestroy();
558     }
559 
560     @Override
onApplyThemeResource(Resources.Theme theme, @StyleRes int resid, boolean first)561     protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid, boolean first) {
562         theme.applyStyle(R.style.SetupWizardPartnerResource, true);
563         super.onApplyThemeResource(theme, resid, first);
564     }
565 
566     @Override
onActivityResult(int requestCode, int resultCode, @Nullable Intent data)567     protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
568         if (requestCode == LAUNCH_CONFIRM_LOCK_ACTIVITY) {
569             onChooseOrConfirmLockResult(false, new ActivityResult(resultCode, data));
570             return;
571         }
572         super.onActivityResult(requestCode, resultCode, data);
573     }
574 
575     @NonNull
576     @Override
getDefaultViewModelCreationExtras()577     public CreationExtras getDefaultViewModelCreationExtras() {
578         final Application application =
579                 super.getDefaultViewModelCreationExtras().get(APPLICATION_KEY);
580         final MutableCreationExtras ret = new MutableCreationExtras();
581         ret.set(APPLICATION_KEY, application);
582 
583         final FingerprintRepository repository = FeatureFactory.getFactory(application)
584                 .getBiometricsRepositoryProvider().getFingerprintRepository(application);
585         ret.set(CHALLENGE_GENERATOR_KEY, new FingerprintChallengeGenerator(repository));
586 
587         ret.set(ENROLLMENT_REQUEST_KEY, new EnrollmentRequest(getIntent(),
588                 getApplicationContext()));
589 
590         Bundle extras = getIntent().getExtras();
591         final CredentialModel credentialModel = new CredentialModel(extras,
592                 SystemClock.elapsedRealtimeClock());
593         ret.set(USER_ID_KEY, credentialModel.getUserId());
594 
595         return ret;
596     }
597 
598     @NonNull
599     @Override
getDefaultViewModelProviderFactory()600     public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
601         return new BiometricsViewModelFactory();
602     }
603 
604     @Override
onAttachedToWindow()605     public void onAttachedToWindow() {
606         super.onAttachedToWindow();
607         getWindow().setStatusBarColor(getBackgroundColor());
608     }
609 
610     @ColorInt
getBackgroundColor()611     private int getBackgroundColor() {
612         final ColorStateList stateList = Utils.getColorAttr(this, android.R.attr.windowBackground);
613         return stateList != null ? stateList.getDefaultColor() : Color.TRANSPARENT;
614     }
615 
616     @Override
onConfigurationChanged(@onNull Configuration newConfig)617     public void onConfigurationChanged(@NonNull Configuration newConfig) {
618         mViewModelProvider.get(DeviceFoldedViewModel.class).onConfigurationChanged(newConfig);
619         super.onConfigurationChanged(newConfig);
620     }
621 
622     @Override
onSaveInstanceState(@onNull Bundle outState)623     protected void onSaveInstanceState(@NonNull Bundle outState) {
624         super.onSaveInstanceState(outState);
625         mViewModel.onSaveInstanceState(outState);
626         mAutoCredentialViewModel.onSaveInstanceState(outState);
627     }
628 }
629