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