2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.settings.fingerprint;
19 import android.app.Activity;
20 import android.app.admin.DevicePolicyManager;
21 import android.content.ActivityNotFoundException;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.hardware.fingerprint.FingerprintManager;
25 import android.graphics.Typeface;
26 import android.graphics.drawable.Drawable;
27 import android.os.Bundle;
28 import android.os.UserHandle;
29 import android.text.Annotation;
30 import android.text.SpannableString;
31 import android.text.SpannableStringBuilder;
32 import android.text.TextPaint;
33 import android.text.method.LinkMovementMethod;
34 import android.text.style.URLSpan;
35 import android.util.Log;
36 import android.view.View;
37 import android.widget.AdapterView;
39 import com.android.internal.logging.MetricsProto.MetricsEvent;
40 import com.android.settings.ChooseLockGeneric;
41 import com.android.settings.ChooseLockSettingsHelper;
42 import com.android.settings.HelpUtils;
43 import com.android.settings.R;
44 import com.android.setupwizardlib.SetupWizardRecyclerLayout;
45 import com.android.setupwizardlib.items.IItem;
46 import com.android.setupwizardlib.items.Item;
47 import com.android.setupwizardlib.items.RecyclerItemAdapter;
50 * Onboarding activity for fingerprint enrollment.
52 public class FingerprintEnrollIntroduction extends FingerprintEnrollBase
53 implements RecyclerItemAdapter.OnItemSelectedListener {
55 protected static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
56 protected static final int FINGERPRINT_FIND_SENSOR_REQUEST = 2;
57 protected static final int LEARN_MORE_REQUEST = 3;
59 private boolean mHasPassword;
62 protected void onCreate(Bundle savedInstanceState) {
63 super.onCreate(savedInstanceState);
64 setContentView(R.layout.fingerprint_enroll_introduction);
65 setHeaderText(R.string.security_settings_fingerprint_enroll_introduction_title);
66 final SetupWizardRecyclerLayout layout =
67 (SetupWizardRecyclerLayout) findViewById(R.id.setup_wizard_layout);
68 final RecyclerItemAdapter adapter = (RecyclerItemAdapter) layout.getAdapter();
69 adapter.setOnItemSelectedListener(this);
70 Item item = (Item) adapter.findItemById(R.id.fingerprint_introduction_message);
71 item.setTitle(LearnMoreSpan.linkify(
72 getText(R.string.security_settings_fingerprint_enroll_introduction_message),
73 getString(R.string.help_url_fingerprint)));
74 // setupwizard library automatically sets the divider inset to
75 // R.dimen.suw_items_icon_divider_inset. We adjust this back to 0 as we do not want
76 // an inset within settings.
77 layout.setDividerInset(0);
78 updatePasswordQuality();
81 private void updatePasswordQuality() {
82 final int passwordQuality = new ChooseLockSettingsHelper(this).utils()
83 .getActivePasswordQuality(mUserId);
84 mHasPassword = passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
88 protected void onNextButtonClick() {
90 // No fingerprints registered, launch into enrollment wizard.
93 // Lock thingy is already set up, launch directly into find sensor step from wizard.
94 launchFindSensor(null);
98 private void launchChooseLock() {
99 Intent intent = getChooseLockIntent();
100 long challenge = getSystemService(FingerprintManager.class).preEnroll();
101 intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
102 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
103 intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
104 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
105 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
106 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
107 if (mUserId != UserHandle.USER_NULL) {
108 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
110 startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
113 private void launchFindSensor(byte[] token) {
114 Intent intent = getFindSensorIntent();
116 intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
118 if (mUserId != UserHandle.USER_NULL) {
119 intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
121 startActivityForResult(intent, FINGERPRINT_FIND_SENSOR_REQUEST);
124 protected Intent getChooseLockIntent() {
125 return new Intent(this, ChooseLockGeneric.class);
128 protected Intent getFindSensorIntent() {
129 Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
134 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
135 final boolean isResultFinished = resultCode == RESULT_FINISHED;
136 if (requestCode == FINGERPRINT_FIND_SENSOR_REQUEST) {
137 if (isResultFinished || resultCode == RESULT_SKIP) {
138 final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
139 setResult(result, data);
143 } else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
144 if (isResultFinished) {
145 updatePasswordQuality();
146 byte[] token = data.getByteArrayExtra(
147 ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
148 launchFindSensor(token);
152 super.onActivityResult(requestCode, resultCode, data);
156 public void onItemSelected(IItem item) {
157 switch (((Item) item).getId()) {
158 case R.id.next_button:
161 case R.id.cancel_button:
162 onCancelButtonClick();
168 protected int getMetricsCategory() {
169 return MetricsEvent.FINGERPRINT_ENROLL_INTRO;
172 protected void onCancelButtonClick() {
176 private static class LearnMoreSpan extends URLSpan {
177 private static final String TAG = "LearnMoreSpan";
178 private static final Typeface TYPEFACE_MEDIUM =
179 Typeface.create("sans-serif-medium", Typeface.NORMAL);
181 private LearnMoreSpan(String url) {
186 public void onClick(View widget) {
187 Context ctx = widget.getContext();
188 Intent intent = HelpUtils.getHelpIntent(ctx, getURL(), ctx.getClass().getName());
190 // This needs to be startActivityForResult even though we do not care about the
191 // actual result because the help app needs to know about who invoked it.
192 widget.startActivityForResult(intent, LEARN_MORE_REQUEST);
193 } catch (ActivityNotFoundException e) {
194 Log.w(LearnMoreSpan.TAG,
195 "Actvity was not found for intent, " + intent.toString());
200 public void updateDrawState(TextPaint ds) {
201 super.updateDrawState(ds);
202 ds.setUnderlineText(false);
203 ds.setTypeface(TYPEFACE_MEDIUM);
206 public static CharSequence linkify(CharSequence rawText, String uri) {
207 SpannableString msg = new SpannableString(rawText);
208 Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
209 SpannableStringBuilder builder = new SpannableStringBuilder(msg);
210 for (Annotation annotation : spans) {
211 int start = msg.getSpanStart(annotation);
212 int end = msg.getSpanEnd(annotation);
213 LearnMoreSpan link = new LearnMoreSpan(uri);
214 builder.setSpan(link, start, end, msg.getSpanFlags(link));