Home | History | Annotate | Download | only in fingerprint
      1 /*
      2  * Copyright (C) 2015 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.fingerprint;
     18 
     19 import android.app.admin.DevicePolicyManager;
     20 import android.content.ActivityNotFoundException;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.graphics.Typeface;
     24 import android.hardware.fingerprint.FingerprintManager;
     25 import android.os.Bundle;
     26 import android.os.UserHandle;
     27 import android.os.UserManager;
     28 import android.text.Annotation;
     29 import android.text.SpannableString;
     30 import android.text.SpannableStringBuilder;
     31 import android.text.TextPaint;
     32 import android.text.TextUtils;
     33 import android.text.style.URLSpan;
     34 import android.util.Log;
     35 import android.view.View;
     36 
     37 import com.android.internal.logging.MetricsProto.MetricsEvent;
     38 import com.android.internal.util.CharSequences;
     39 import com.android.settings.ChooseLockGeneric;
     40 import com.android.settings.ChooseLockSettingsHelper;
     41 import com.android.settingslib.HelpUtils;
     42 import com.android.settings.R;
     43 import com.android.setupwizardlib.SetupWizardRecyclerLayout;
     44 import com.android.setupwizardlib.items.IItem;
     45 import com.android.setupwizardlib.items.Item;
     46 import com.android.setupwizardlib.items.RecyclerItemAdapter;
     47 
     48 /**
     49  * Onboarding activity for fingerprint enrollment.
     50  */
     51 public class FingerprintEnrollIntroduction extends FingerprintEnrollBase
     52         implements RecyclerItemAdapter.OnItemSelectedListener {
     53 
     54     protected static final int CHOOSE_LOCK_GENERIC_REQUEST = 1;
     55     protected static final int FINGERPRINT_FIND_SENSOR_REQUEST = 2;
     56     protected static final int LEARN_MORE_REQUEST = 3;
     57 
     58     private UserManager mUserManager;
     59     private boolean mHasPassword;
     60 
     61     @Override
     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         mUserManager = UserManager.get(this);
     69         final RecyclerItemAdapter adapter = (RecyclerItemAdapter) layout.getAdapter();
     70         adapter.setOnItemSelectedListener(this);
     71         Item item = (Item) adapter.findItemById(R.id.fingerprint_introduction_message);
     72         item.setTitle(LearnMoreSpan.linkify(
     73                 getText(R.string.security_settings_fingerprint_enroll_introduction_message),
     74                 getString(R.string.help_url_fingerprint)));
     75         // setupwizard library automatically sets the divider inset to
     76         // R.dimen.suw_items_icon_divider_inset. We adjust this back to 0 as we do not want
     77         // an inset within settings.
     78         layout.setDividerInset(0);
     79         updatePasswordQuality();
     80     }
     81 
     82     private void updatePasswordQuality() {
     83         final int passwordQuality = new ChooseLockSettingsHelper(this).utils()
     84                 .getActivePasswordQuality(mUserManager.getCredentialOwnerProfile(mUserId));
     85         mHasPassword = passwordQuality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
     86     }
     87 
     88     @Override
     89     protected void onNextButtonClick() {
     90         if (!mHasPassword) {
     91             // No fingerprints registered, launch into enrollment wizard.
     92             launchChooseLock();
     93         } else {
     94             // Lock thingy is already set up, launch directly into find sensor step from wizard.
     95             launchFindSensor(null);
     96         }
     97     }
     98 
     99     private void launchChooseLock() {
    100         Intent intent = getChooseLockIntent();
    101         long challenge = getSystemService(FingerprintManager.class).preEnroll();
    102         intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.MINIMUM_QUALITY_KEY,
    103                 DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);
    104         intent.putExtra(ChooseLockGeneric.ChooseLockGenericFragment.HIDE_DISABLED_PREFS, true);
    105         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, true);
    106         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, challenge);
    107         intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, true);
    108         if (mUserId != UserHandle.USER_NULL) {
    109             intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
    110         }
    111         startActivityForResult(intent, CHOOSE_LOCK_GENERIC_REQUEST);
    112     }
    113 
    114     private void launchFindSensor(byte[] token) {
    115         Intent intent = getFindSensorIntent();
    116         if (token != null) {
    117             intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, token);
    118         }
    119         if (mUserId != UserHandle.USER_NULL) {
    120             intent.putExtra(Intent.EXTRA_USER_ID, mUserId);
    121         }
    122         startActivityForResult(intent, FINGERPRINT_FIND_SENSOR_REQUEST);
    123     }
    124 
    125     protected Intent getChooseLockIntent() {
    126         return new Intent(this, ChooseLockGeneric.class);
    127     }
    128 
    129     protected Intent getFindSensorIntent() {
    130         Intent intent = new Intent(this, FingerprintEnrollFindSensor.class);
    131         return intent;
    132     }
    133 
    134     @Override
    135     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    136         final boolean isResultFinished = resultCode == RESULT_FINISHED;
    137         if (requestCode == FINGERPRINT_FIND_SENSOR_REQUEST) {
    138             if (isResultFinished || resultCode == RESULT_SKIP) {
    139                 final int result = isResultFinished ? RESULT_OK : RESULT_SKIP;
    140                 setResult(result, data);
    141                 finish();
    142                 return;
    143             }
    144         } else if (requestCode == CHOOSE_LOCK_GENERIC_REQUEST) {
    145             if (isResultFinished) {
    146                 updatePasswordQuality();
    147                 byte[] token = data.getByteArrayExtra(
    148                         ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN);
    149                 launchFindSensor(token);
    150                 return;
    151             }
    152         }
    153         super.onActivityResult(requestCode, resultCode, data);
    154     }
    155 
    156     @Override
    157     public void onItemSelected(IItem item) {
    158         switch (((Item) item).getId()) {
    159             case R.id.next_button:
    160                 onNextButtonClick();
    161                 break;
    162             case R.id.cancel_button:
    163                 onCancelButtonClick();
    164                 break;
    165         }
    166     }
    167 
    168     @Override
    169     protected int getMetricsCategory() {
    170         return MetricsEvent.FINGERPRINT_ENROLL_INTRO;
    171     }
    172 
    173     protected void onCancelButtonClick() {
    174         finish();
    175     }
    176 
    177     private static class LearnMoreSpan extends URLSpan {
    178         private static final String TAG = "LearnMoreSpan";
    179         private static final Typeface TYPEFACE_MEDIUM =
    180                 Typeface.create("sans-serif-medium", Typeface.NORMAL);
    181 
    182         private LearnMoreSpan(String url) {
    183             super(url);
    184         }
    185 
    186         @Override
    187         public void onClick(View widget) {
    188             Context ctx = widget.getContext();
    189             Intent intent = HelpUtils.getHelpIntent(ctx, getURL(), ctx.getClass().getName());
    190             try {
    191                 // This needs to be startActivityForResult even though we do not care about the
    192                 // actual result because the help app needs to know about who invoked it.
    193                 widget.startActivityForResult(intent, LEARN_MORE_REQUEST);
    194             } catch (ActivityNotFoundException e) {
    195                 Log.w(LearnMoreSpan.TAG,
    196                         "Actvity was not found for intent, " + intent.toString());
    197             }
    198         }
    199 
    200         @Override
    201         public void updateDrawState(TextPaint ds) {
    202             super.updateDrawState(ds);
    203             ds.setUnderlineText(false);
    204             ds.setTypeface(TYPEFACE_MEDIUM);
    205         }
    206 
    207         public static CharSequence linkify(CharSequence rawText, String uri) {
    208             SpannableString msg = new SpannableString(rawText);
    209             Annotation[] spans = msg.getSpans(0, msg.length(), Annotation.class);
    210             if (TextUtils.isEmpty(uri)) {
    211                 CharSequence ret = rawText;
    212                 for (Annotation annotation : spans) {
    213                     int start = msg.getSpanStart(annotation);
    214                     int end = msg.getSpanEnd(annotation);
    215                     ret = TextUtils.concat(ret.subSequence(0, start),
    216                             msg.subSequence(end, msg.length()));
    217                 }
    218                 return ret;
    219             } else {
    220                 SpannableStringBuilder builder = new SpannableStringBuilder(msg);
    221                 for (Annotation annotation : spans) {
    222                     int start = msg.getSpanStart(annotation);
    223                     int end = msg.getSpanEnd(annotation);
    224                     LearnMoreSpan link = new LearnMoreSpan(uri);
    225                     builder.setSpan(link, start, end, msg.getSpanFlags(link));
    226                 }
    227                 return builder;
    228             }
    229         }
    230     }
    231 }
    232