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; 18 19 import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; 20 21 import android.annotation.Nullable; 22 import android.content.Intent; 23 import android.content.res.Resources; 24 import android.graphics.Color; 25 import android.os.Bundle; 26 import android.os.UserHandle; 27 import android.text.TextUtils; 28 import android.view.View; 29 import android.widget.TextView; 30 31 import com.android.settings.R; 32 import com.android.settings.SetupWizardUtils; 33 import com.android.settings.biometrics.fingerprint.FingerprintEnrollEnrolling; 34 import com.android.settings.core.InstrumentedActivity; 35 import com.android.settings.password.ChooseLockSettingsHelper; 36 37 import com.google.android.setupcompat.template.FooterBarMixin; 38 import com.google.android.setupcompat.template.FooterButton; 39 import com.google.android.setupdesign.GlifLayout; 40 41 /** 42 * Base activity for all biometric enrollment steps. 43 */ 44 public abstract class BiometricEnrollBase extends InstrumentedActivity { 45 46 public static final String EXTRA_FROM_SETTINGS_SUMMARY = "from_settings_summary"; 47 public static final String EXTRA_KEY_LAUNCHED_CONFIRM = "launched_confirm_lock"; 48 public static final String EXTRA_KEY_REQUIRE_VISION = "accessibility_vision"; 49 public static final String EXTRA_KEY_REQUIRE_DIVERSITY = "accessibility_diversity"; 50 51 /** 52 * Used by the choose fingerprint wizard to indicate the wizard is 53 * finished, and each activity in the wizard should finish. 54 * <p> 55 * Previously, each activity in the wizard would finish itself after 56 * starting the next activity. However, this leads to broken 'Back' 57 * behavior. So, now an activity does not finish itself until it gets this 58 * result. 59 */ 60 public static final int RESULT_FINISHED = RESULT_FIRST_USER; 61 62 /** 63 * Used by the enrolling screen during setup wizard to skip over setting up fingerprint, which 64 * will be useful if the user accidentally entered this flow. 65 */ 66 public static final int RESULT_SKIP = RESULT_FIRST_USER + 1; 67 68 /** 69 * Like {@link #RESULT_FINISHED} except this one indicates enrollment failed because the 70 * device was left idle. This is used to clear the credential token to require the user to 71 * re-enter their pin/pattern/password before continuing. 72 */ 73 public static final int RESULT_TIMEOUT = RESULT_FIRST_USER + 2; 74 75 public static final int CHOOSE_LOCK_GENERIC_REQUEST = 1; 76 public static final int BIOMETRIC_FIND_SENSOR_REQUEST = 2; 77 public static final int LEARN_MORE_REQUEST = 3; 78 public static final int CONFIRM_REQUEST = 4; 79 public static final int ENROLL_REQUEST = 5; 80 81 protected boolean mLaunchedConfirmLock; 82 protected byte[] mToken; 83 protected int mUserId; 84 protected boolean mFromSettingsSummary; 85 protected FooterBarMixin mFooterBarMixin; 86 87 @Override onCreate(Bundle savedInstanceState)88 protected void onCreate(Bundle savedInstanceState) { 89 super.onCreate(savedInstanceState); 90 mToken = getIntent().getByteArrayExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); 91 mFromSettingsSummary = getIntent().getBooleanExtra(EXTRA_FROM_SETTINGS_SUMMARY, false); 92 if (savedInstanceState != null && mToken == null) { 93 mLaunchedConfirmLock = savedInstanceState.getBoolean(EXTRA_KEY_LAUNCHED_CONFIRM); 94 mToken = savedInstanceState.getByteArray( 95 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN); 96 mFromSettingsSummary = 97 savedInstanceState.getBoolean(EXTRA_FROM_SETTINGS_SUMMARY, false); 98 } 99 mUserId = getIntent().getIntExtra(Intent.EXTRA_USER_ID, UserHandle.myUserId()); 100 } 101 102 @Override onApplyThemeResource(Resources.Theme theme, int resid, boolean first)103 protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) { 104 resid = SetupWizardUtils.getTheme(getIntent()); 105 theme.applyStyle(R.style.SetupWizardPartnerResource, true); 106 super.onApplyThemeResource(theme, resid, first); 107 } 108 109 @Override onSaveInstanceState(Bundle outState)110 protected void onSaveInstanceState(Bundle outState) { 111 super.onSaveInstanceState(outState); 112 outState.putBoolean(EXTRA_KEY_LAUNCHED_CONFIRM, mLaunchedConfirmLock); 113 outState.putByteArray(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); 114 outState.putBoolean(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary); 115 } 116 117 @Override onPostCreate(@ullable Bundle savedInstanceState)118 protected void onPostCreate(@Nullable Bundle savedInstanceState) { 119 super.onPostCreate(savedInstanceState); 120 initViews(); 121 } 122 initViews()123 protected void initViews() { 124 getWindow().setStatusBarColor(Color.TRANSPARENT); 125 } 126 getLayout()127 protected GlifLayout getLayout() { 128 return (GlifLayout) findViewById(R.id.setup_wizard_layout); 129 } 130 setHeaderText(int resId, boolean force)131 protected void setHeaderText(int resId, boolean force) { 132 TextView layoutTitle = getLayout().getHeaderTextView(); 133 CharSequence previousTitle = layoutTitle.getText(); 134 CharSequence title = getText(resId); 135 if (previousTitle != title || force) { 136 if (!TextUtils.isEmpty(previousTitle)) { 137 layoutTitle.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE); 138 } 139 getLayout().setHeaderText(title); 140 setTitle(title); 141 } 142 } 143 setHeaderText(int resId)144 protected void setHeaderText(int resId) { 145 setHeaderText(resId, false /* force */); 146 } 147 getNextButton()148 protected FooterButton getNextButton() { 149 if (mFooterBarMixin != null) { 150 return mFooterBarMixin.getPrimaryButton(); 151 } 152 return null; 153 } 154 onNextButtonClick(View view)155 protected void onNextButtonClick(View view) { 156 } 157 getFingerprintEnrollingIntent()158 protected Intent getFingerprintEnrollingIntent() { 159 Intent intent = new Intent(); 160 intent.setClassName(SETTINGS_PACKAGE_NAME, FingerprintEnrollEnrolling.class.getName()); 161 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); 162 intent.putExtra(EXTRA_FROM_SETTINGS_SUMMARY, mFromSettingsSummary); 163 if (mUserId != UserHandle.USER_NULL) { 164 intent.putExtra(Intent.EXTRA_USER_ID, mUserId); 165 } 166 return intent; 167 } 168 launchConfirmLock(int titleResId, long challenge)169 protected void launchConfirmLock(int titleResId, long challenge) { 170 ChooseLockSettingsHelper helper = new ChooseLockSettingsHelper(this); 171 boolean launchedConfirmationActivity; 172 if (mUserId == UserHandle.USER_NULL) { 173 launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST, 174 getString(titleResId), 175 null, null, challenge, true /* foregroundOnly */); 176 } else { 177 launchedConfirmationActivity = helper.launchConfirmationActivity(CONFIRM_REQUEST, 178 getString(titleResId), 179 null, null, challenge, mUserId, true /* foregroundOnly */); 180 } 181 if (!launchedConfirmationActivity) { 182 // This shouldn't happen, as we should only end up at this step if a lock thingy is 183 // already set. 184 finish(); 185 } else { 186 mLaunchedConfirmLock = true; 187 } 188 } 189 } 190