Setting 选择密码解析(一)

选择解锁方式页面的加载

首先还是从ChooseLockGenericFragment开始分析,由上一篇链接 我们知道当第一次选择密码时,会执行helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)方法并返回false,从而执行updatePreferencesOrFinish(savedInstanceState != null);这个方法,我们来看下此方法,代码如下:

private void updatePreferencesOrFinish(boolean isRecreatingActivity) {
            Intent intent = getActivity().getIntent();
            int quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
            Log.d("faceid", "quality = " + quality+ " :isRecreatingActivity: "+isRecreatingActivity);
            //由于没有设置过密码,此时quality为-1
    			if (quality == -1) {
                // If caller didn't specify password quality, show UI and allow the user to choose.
                quality = intent.getIntExtra(MINIMUM_QUALITY_KEY, -1);
                quality = mController.upgradeQuality(quality);//quality:0
                final boolean hideDisabledPrefs = intent.getBooleanExtra(
                        HIDE_DISABLED_PREFS, false);//hideDisabledPrefs false
                final PreferenceScreen prefScreen = getPreferenceScreen();
                if (prefScreen != null) {
                    prefScreen.removeAll();
                }
                addPreferences();//添加布局
                removePreferencesForFaceid();
                disableUnusablePreferences(quality, hideDisabledPrefs); //如果此时是人脸跳到此页面时hideDisabledPrefs为true,会disable 无和滑动两种锁屏方式
                updatePreferenceText();//更新每个解锁方式的文字
                updateCurrentPreference();//更新当前选中的解锁方式的文字状态
                updatePreferenceSummaryIfNeeded();
            } else if (!isRecreatingActivity) { //todo  为什么不走这里
                // Don't start the activity again if we are recreated for configuration change
                updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
            }
        }

此时布局已经加载完成,界面截图如下:
Setting 选择密码解析(一)_第1张图片

选择解锁方式

当选择解锁方式时,点击任意一种都会执行onPreferenceTreeClick方法,我们来看下,如果我们选择patten,会执行甚麽,代码如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/password/ChooseLockGeneric.java/ChooseLockGenericFragment
@Override
        public boolean onPreferenceTreeClick(Preference preference) {
            final String key = preference.getKey();//此时key为:unlock_set_pattern
           	//isUnlockMethodSecure会判断key是否为none或者swipe,此时key为pattern,返回false
            if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
                ......
            } else if (KEY_SKIP_FINGERPRINT.equals(key)) {
                ......
            } else {
                //此时会执行setUnlockMethod(unlock_set_pattern)方法
                return setUnlockMethod(key);
            }
        }

接着来看setUnlockMethod方法,代码如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/password/ChooseLockGeneric.java/ChooseLockGenericFragment
private boolean setUnlockMethod(String unlockMethod) {
            EventLog.writeEvent(EventLogTags.LOCK_SCREEN_TYPE, unlockMethod);
            //此时的unlockMethod为unlock_set_pattern,所以lock为PATTERN
            ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
            if (lock != null) {
                switch (lock) {
                    case NONE:
                    case SWIPE:
                       ......
                        return true;
                    case PATTERN:
                    case PIN:
                    case PASSWORD:
                    case MANAGED:
                        //所以会执行此方法
                        maybeEnableEncryption(lock.defaultQuality, false);
                        return true;
                }
            }
            return false;
        }

接着我们来看下maybeEnableEncryption(lock.defaultQuality, false);方法,方法如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/password/ChooseLockGeneric.java/ChooseLockGenericFragment
private void maybeEnableEncryption(int quality, boolean disabled) {
            DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
            if (UserManager.get(getActivity()).isAdminUser()
                    && mUserId == UserHandle.myUserId()
                    && LockPatternUtils.isDeviceEncryptionEnabled()
                    && !LockPatternUtils.isFileEncryptionEnabled()
                    && !dpm.getDoNotAskCredentialsOnBoot()) {
                //此时的quality为65535为图案
                mEncryptionRequestQuality = quality;
                //mEncryptionRequestDisabled为false
                mEncryptionRequestDisabled = disabled;
               //此时获取到的intent为ChooseLockPattern.java
                Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
                //mForChangeCredRequiredForBoot为false
                unlockMethodIntent.putExtra(
                        ChooseLockSettingsHelper.EXTRA_KEY_FOR_CHANGE_CRED_REQUIRED_FOR_BOOT,
                        mForChangeCredRequiredForBoot);
                final Context context = getActivity();
                // If accessibility is enabled and the user hasn't seen this dialog before, set the
                // default state to agree with that which is compatible with accessibility
                // (password not required).
                final boolean accEn = AccessibilityManager.getInstance(context).isEnabled();
                final boolean required = mLockPatternUtils.isCredentialRequiredToDecrypt(!accEn);
                //此方法新建里个Intent,值为EncryptionInterstitial.class,并将unlockMethodIntent
                //作为参数放到此intent中。
                Intent intent = getEncryptionInterstitialIntent(context, quality, required,
                        unlockMethodIntent);
                //mForFingerprint为:false
                intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT,
                        mForFingerprint);
                //mHideDrawer为:false
                intent.putExtra(EXTRA_HIDE_DRAWER, mHideDrawer);
                startActivityForResult(
                        intent,
                        mIsSetNewPassword && mHasChallenge
                                ? CHOOSE_LOCK_BEFORE_FINGERPRINT_REQUEST
                                : ENABLE_ENCRYPTION_REQUEST);
            } else {
                ......
            }
        }

安全启动页面

此时执行startActivityForResult跳转到EncryptionInterstitial.java,页面截图如下:
Setting 选择密码解析(一)_第2张图片
接着上面来看,由于EncryptionInterstitial继承SettingsActivity,所以打印log如下:
Setting 选择密码解析(一)_第3张图片
所以下面我们来看看EncryptionInterstitialFragment,代码如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/EncryptionInterstitial.java/EncryptionInterstitialFragment 
@Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);

            /* M: fragment lifecycle should be same as Activity lifecycle */
            Log.d(TAG, "EncryptionInterstitialFragment onViewCreated,  isActivityFinishing: "
                  + (getActivity().isFinishing()) + "isActivity Destroyed: "
                  + (getActivity().isDestroyed()) + "Monkey user :" + Utils.isMonkeyRunning());

            ......
			//右下方的是按钮,点击后会跳转到设置解锁图案页面
            mRequirePasswordToDecrypt = view.findViewById(R.id.encrypt_require_password);
            //左下方的否按钮,点击会返回
            mDontRequirePasswordToDecrypt = view.findViewById(R.id.encrypt_dont_require_password);
           	//获取intent里的参数,由前面可知为false
            boolean forFingerprint = getActivity().getIntent().getBooleanExtra(
                    ChooseLockSettingsHelper.EXTRA_KEY_FOR_FINGERPRINT, false);
            Intent intent = getActivity().getIntent();
            //65536,为图案
            mRequestedPasswordQuality = intent.getIntExtra(EXTRA_PASSWORD_QUALITY, 0);
            //此mUnlockMethodIntent为ChooseLockPattern.java
            mUnlockMethodIntent = intent.getParcelableExtra(EXTRA_UNLOCK_METHOD_INTENT);
            final int msgId;
            switch (mRequestedPasswordQuality) {
                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                    //此时forFingerprint为false,所以msgId为:R.string.encryption_interstitial_message_pattern;
                    //即:"为了进一步保护此设备的安全,您可以将设备设为需要绘制解锁图案才能启动。在设备启动之前,
                    //无法接听电话、接收消息或通知(包括闹钟)。\n\n这样一来,即使设备丢失或被盗,
                    //其中的数据仍安全无虞。要将设备设为需要绘制解锁图案才能启动吗?"
                    msgId = forFingerprint ?
                            R.string.encryption_interstitial_message_pattern_for_fingerprint :
                            R.string.encryption_interstitial_message_pattern;
                    break;
                ......
            }
            
            TextView message = (TextView) getActivity().findViewById(R.id.encryption_message);
            //为TextView 设置值
            message.setText(msgId);
			//为这两个按钮设置点击事件
            mRequirePasswordToDecrypt.setOnClickListener(this);
            mDontRequirePasswordToDecrypt.setOnClickListener(this);
			......

           
        }

接着我们看下这两个按钮的点击事件,方法如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/EncryptionInterstitial.java/EncryptionInterstitialFragment
@Override
        public void onClick(View view) {
            //点击右下角 是 按钮
            if (view == mRequirePasswordToDecrypt) {
                //log显示accEn为false
                final boolean accEn = AccessibilityManager.getInstance(getActivity()).isEnabled();
                if (accEn && !mPasswordRequired) {
                    ......
                } else {
                    //此时会执行到这里
                    //setRequirePasswordState方法就是将参数true赋值给mPasswordRequired
                    //此时mPasswordRequired = true
                    setRequirePasswordState(true);
                    startLockIntent();
                }
            } else {
                setRequirePasswordState(false);
                startLockIntent();
            }
        }

接着我们看下startLockIntent();方法,方法如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/EncryptionInterstitial.java/EncryptionInterstitialFragment
protected void startLockIntent() {
    		//此时的mUnlockMethodIntent即为上面intent获取的参数
    		//此时mUnlockMethodIntent值为ChooseLockPattern.java
            if (mUnlockMethodIntent != null) {
                //mPasswordRequired为true
                mUnlockMethodIntent.putExtra(EXTRA_REQUIRE_PASSWORD, mPasswordRequired);
                //CHOOSE_LOCK_REQUEST 为100
                startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST);
            } else {
                Log.wtf(TAG, "no unlock intent to start");
                finish();
            }
        }

此时将执行startActivityForResult(mUnlockMethodIntent, CHOOSE_LOCK_REQUEST);跳转到ChooseLockPattern.java进行图案密码的输入,页面截图如下:
Setting 选择密码解析(一)_第4张图片

图案密码输入页面

我们首先看下onViewCreated生命周期,代码如下:

@Override
        public void onViewCreated(View view, Bundle savedInstanceState) {
            super.onViewCreated(view, savedInstanceState);
           	//控件的一些初始化
            ......
            //绘制图案密码的监听
            mLockPatternView.setOnPatternListener(制图案密码的监听);
            //为左下方和右下方按钮设置点击事件的监听
            mFooterLeftButton.setOnClickListener(this);
            mFooterRightButton.setOnClickListener(this);
			//confirmCredentials为:false
            final boolean confirmCredentials = getActivity().getIntent()
                    .getBooleanExtra(ChooseLockGeneric.CONFIRM_CREDENTIALS, true);
            Intent intent = getActivity().getIntent();
            //mCurrentPattern为:null
            mCurrentPattern = intent.getStringExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD);//null
            //mHasChallenge为:false
            mHasChallenge = intent.getBooleanExtra(
                    ChooseLockSettingsHelper.EXTRA_KEY_HAS_CHALLENGE, false);
            //mChallenge为:false
            mChallenge = intent.getLongExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE, 0);
			//由于第一次进入,此时savedInstanceState为null
            if (savedInstanceState == null) {
                //confirmCredentials此时为false
                if (confirmCredentials) {
                    ......
                } else {
                    //此时会执行updateStage
                    updateStage(Stage.Introduction);
                }
            } else {
               ......
            }
        }

首先我们看下stage是什么,其实stage 表示当用户选择一个patten时,用户此时的状态。
由下面可知,stage是一个枚举,分别有Introduction、NeedToConfirm、ChoiceConfirmed、FirstChoiceValid等几种状态,每种状态里面的参数如下所示,其实就是绘制密码界面所需要的一些控件的值。
接着我们来看下updateStage(Stage.Introduction);方法,看下第一次绘制时会执行什么,截图如下:
Setting 选择密码解析(一)_第5张图片
方法如下:

protected void updateStage(Stage stage) {
            //第一次进入时stage为:Stage.Introduction
    		//定义一个变量保存之前的state
    		final Stage previousStage = mUiStage;
			//当前的状态
            mUiStage = stage;

            // header text, footer text, visibility and
            // enabled state all known from the stage
            if (stage == Stage.ChoiceTooShort) {
                mHeaderText.setText(
                        getResources().getString(
                                stage.headerMessage,
                                LockPatternUtils.MIN_LOCK_PATTERN_SIZE));
            } else {
                //此时Introduction.headerMessage为:"绘制解锁图案"
                mHeaderText.setText(stage.headerMessage);
            }
    		//由上面可知,此时的mForFingerprint为false
            int message = mForFingerprint ? stage.messageForFingerprint : stage.message;
            //此时message为:"为了安全起见,请设置解锁图案",ID_EMPTY_MESSAGE = -1
    		if (message == ID_EMPTY_MESSAGE) {
                mMessageText.setText("");
            } else {
                //所以会执行这里,赋值给mMessageText
                mMessageText.setText(message);
            }
    		//Introduction.footerMessage为ID_EMPTY_MESSAGE,即-1
            if (stage.footerMessage == ID_EMPTY_MESSAGE) {
                //执行这里,设置为空字符
                mFooterText.setText("");
            } else {
                mFooterText.setText(stage.footerMessage);
            }

            if (stage == Stage.ConfirmWrong || stage == Stage.ChoiceTooShort) {
                TypedValue typedValue = new TypedValue();
                Theme theme = getActivity().getTheme();
                theme.resolveAttribute(R.attr.colorError, typedValue, true);
                mHeaderText.setTextColor(typedValue.data);

            } else {
                //为mHeaderText设置字体颜色
                if (mDefaultHeaderColorList != null) {
                    mHeaderText.setTextColor(mDefaultHeaderColorList);
                }

                if (stage == Stage.NeedToConfirm && mForFingerprint) {
                    mHeaderText.setText("");
                    mTitleText.setText(R.string.lockpassword_draw_your_pattern_again_header);
                }
            }
			//更新左下方按钮的状态
            updateFooterLeftButton(stage, mFooterLeftButton);
			//设置右下方按钮的文字
            setRightButtonText(stage.rightMode.text);
    		//设置右下方按钮的是否可用,即是否可点击
            setRightButtonEnabled(stage.rightMode.enabled);

            // Introduction.patternEnabled为true
            if (stage.patternEnabled) {
                mLockPatternView.enableInput();
            } else {
                mLockPatternView.disableInput();
            }

            // the rest of the stuff varies enough that it is easier just to handle
            // on a case by case basis.
            mLockPatternView.setDisplayMode(DisplayMode.Correct);
            boolean announceAlways = false;

            switch (mUiStage) {
                case Introduction:
                    //mUiStage为Introduction,执行这里,进行一个清除Pattern的动作,
                    mLockPatternView.clearPattern();
                    break;
                case HelpScreen:
                    mLockPatternView.setPattern(DisplayMode.Animate, mAnimatePattern);
                    break;
                case ChoiceTooShort:
                    mLockPatternView.setDisplayMode(DisplayMode.Wrong);
                    postClearPatternRunnable();
                    announceAlways = true;
                    break;
                case FirstChoiceValid:
                    break;
                case NeedToConfirm:
                    mLockPatternView.clearPattern();
                    break;
                case ConfirmWrong:
                    mLockPatternView.setDisplayMode(DisplayMode.Wrong);
                    postClearPatternRunnable();
                    announceAlways = true;
                    break;
                case ChoiceConfirmed:
                    break;
            }

    		//当状态改变时,设置mHeaderText状态可以改变
            if (previousStage != stage || announceAlways) {
                mHeaderText.announceForAccessibility(mHeaderText.getText());
            }
        }

接着我们看下onResume方法,当用户交互时会调用此方法,方法如下:

@Override
        public void onResume() {
            super.onResume();
            updateStage(mUiStage);
			//一个后台fragment,用来跟踪保存和校验用户选择的密码(pattern/pin/password).
            if (mSaveAndFinishWorker != null) {
                setRightButtonEnabled(false);
                //设置监听器,当两次密码输入完成保存成功后,激活监听器跳转到通知页面
                mSaveAndFinishWorker.setListener(this);
            }
        }

可以看到,当用户进行交互,即绘制图案时,会不断的调用updateStage(mUiStage);来更新界面状态。且第一次进入时即mUiStage为Introduction时,会进行一个pattern的初始化动作,清除图案保证没有绘制过。
接下来我们看下绘制图案密码的监听mLockPatternView.setOnPatternListener

protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
                new LockPatternView.OnPatternListener() {
				//开始绘制图案时调用
                public void onPatternStart() {
                    mLockPatternView.removeCallbacks(mClearPatternRunnable);
                    patternInProgress();
                }
				//清除图案时调用
                public void onPatternCleared() {
                    //mClearPatternRunnable为一个Runnable,调用了mLockPatternView.clearPattern();
                    mLockPatternView.removeCallbacks(mClearPatternRunnable);
                }
				//图案绘制完成时调用
                public void onPatternDetected(List pattern) {
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                        if (mChosenPattern == null) throw new IllegalStateException(
                                "null chosen pattern in stage 'need to confirm");
                        if (mChosenPattern.equals(pattern)) {
                            updateStage(Stage.ChoiceConfirmed);
                        } else {
                            updateStage(Stage.ConfirmWrong);
                        }
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                        //此处的pattern为一个二维数组,Cell[][],即代表的是一个3x3的矩阵
                        //public static final int MIN_LOCK_PATTERN_SIZE = 4;
                        if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                            updateStage(Stage.ChoiceTooShort);
                        } else {
                            mChosenPattern = new ArrayList(pattern);
                            updateStage(Stage.FirstChoiceValid);
                        }
                    } else {
                        throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
                                + "entering the pattern.");
                    }
                }

                public void onPatternCellAdded(List pattern) {
					//空实现
                }
				//开始绘制时由onPatternStart调用 ,主要作用为页面一些文字属性更新
                private void patternInProgress() {
                    mHeaderText.setText(R.string.lockpattern_recording_inprogress);//"完成后松开手指"
                    if (mDefaultHeaderColorList != null) {
                        mHeaderText.setTextColor(mDefaultHeaderColorList);
                    }
                    mFooterText.setText("");
                    mFooterLeftButton.setEnabled(false);
                    mFooterRightButton.setEnabled(false);

                    if (mTitleHeaderScrollView != null) {
                        mTitleHeaderScrollView.post(new Runnable() {
                            @Override
                            public void run() {
                                mTitleHeaderScrollView.fullScroll(ScrollView.FOCUS_DOWN);
                            }
                        });
                    }
                }
         };

所以到这里便有了一个大概的思路,mChooseNewLockPatternListener监听用户行为,是否进行绘制图案,当开始绘制时,触发onPatternStart,onPatternStart又接着调用patternInProgress来更新UI,绘制过程中界面如下:
Setting 选择密码解析(一)_第6张图片
当绘制完成时,调用onPatternDetected,我们看下第一次绘制完成,此方法做了什么,方法如下:

protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
                new LockPatternView.OnPatternListener() {
				......
				//图案绘制完成时调用
                public void onPatternDetected(List pattern) {
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                        ......
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                        //第一次绘制时mUiStage为Introduction,所以会执行到这里
                        //当绘制完成时,pattern.size()为5
                        if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                            updateStage(Stage.ChoiceTooShort);
                        } else {
                            //此时会执行到这里
                            mChosenPattern = new ArrayList(pattern);
                            updateStage(Stage.FirstChoiceValid);
                        }
                    } else {
                        throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
                                + "entering the pattern.");
                    }
                }

               ......
         };

接着调用updateStage(Stage.FirstChoiceValid);即上面的方法,可以看到,此时updateStage方法仅仅是做了一些更新UI的操作,比如设置buttun的状态和字体以及header的文字等,我们可以看下此时的页面,页面如下:
Setting 选择密码解析(一)_第7张图片
此时状态为Stage.FirstChoiceValid,当点击下一步时,执行onclick方法如下:

public void onClick(View v) {
            if (v == mFooterLeftButton) {
                handleLeftButton();
            } else if (v == mFooterRightButton) {
                handleRightButton();
            }
        }

handleRightButton();方法如下:


public void handleRightButton() {
    		//由于此时mUiStage为FirstChoiceValid,他的rightMode为Continue
            if (mUiStage.rightMode == RightButtonMode.Continue) {
                if (mUiStage != Stage.FirstChoiceValid) {
                    throw new IllegalStateException("expected ui stage "
                            + Stage.FirstChoiceValid + " when button is "
                            + RightButtonMode.Continue);
                }
                updateStage(Stage.NeedToConfirm);
            } else if (mUiStage.rightMode == RightButtonMode.Confirm) {
               ......
            } else if (mUiStage.rightMode == RightButtonMode.Ok) {
                ......
            }
        }
        

第二次输入密码

可以看到又执行updateStage(Stage.NeedToConfirm),在这个方法中便会调用mLockPatternView.clearPattern重置UI,让用户重新绘制。此时用户界面为:
Setting 选择密码解析(一)_第8张图片
当第二次绘制完成时,此时会再调用onPatternDetected,我们来看下此时的方法,方法如下:

public void onPatternDetected(List pattern) {
    				//由于上面调用了updateStage(Stage.NeedToConfirm),此方法里面会将mUiStage
    				//赋值为Stage.NeedToConfirm
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                        if (mChosenPattern == null) throw new IllegalStateException(
                                "null chosen pattern in stage 'need to confirm");
                        //此时判断当前绘制的图案是否和上次绘制一样
                        if (mChosenPattern.equals(pattern)) {
                            //一样则会调用
                            updateStage(Stage.ChoiceConfirmed);
                        } else {
                            updateStage(Stage.ConfirmWrong);
                        }
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                       ......
                    } else {
                        ......
                    }
                }

可以看到会调用updateStage(Stage.ChoiceConfirmed);来更新UI,我们看下当两次绘制图案一样时,此时用户界面是什么,截图如下:
Setting 选择密码解析(一)_第9张图片

疑问:两次绘制的密码是怎么保存的?

我们来看下当第一次绘制完密码时,调用onPatternDetected,我们看下此时代码:

public void onPatternDetected(List pattern) {
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                       ......
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                        if (pattern.size() < LockPatternUtils.MIN_LOCK_PATTERN_SIZE) {
                            ......
                        } else {
                            //新建一个ArrayList将绘制完成的pattern保存到此mChosenPattern
                            mChosenPattern = new ArrayList(pattern);
                            updateStage(Stage.FirstChoiceValid);
                        }
                    } else {
                        ......
                    }
                }

可以看到此时会新建一个ArrayList将第一次绘制完成的pattern保存到此mChosenPattern,用来做第二次绘制完成密码时的判断,即

protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
                new LockPatternView.OnPatternListener() {
    
                public void onPatternDetected(List pattern) {
                    if (mUiStage == Stage.NeedToConfirm || mUiStage == Stage.ConfirmWrong) {
                        if (mChosenPattern == null) throw new IllegalStateException(
                                "null chosen pattern in stage 'need to confirm");
                        if (mChosenPattern.equals(pattern)) {
                            updateStage(Stage.ChoiceConfirmed);
                        } else {
                            updateStage(Stage.ConfirmWrong);
                        }
                    } else if (mUiStage == Stage.Introduction || mUiStage == Stage.ChoiceTooShort){
                       ......
                    } else {
                       ......
                    }
                }
               
         };

可以看到调用mChosenPattern.equals(pattern)来进行判断两次绘制的是否一样。

绘制两次完成

接着来看,当绘制两次相同的密码后,我们点击确认按钮后,执行onclick方法,调用handleRightButton();方法如下:

public void handleRightButton() {
            if (mUiStage.rightMode == RightButtonMode.Continue) {
                .....
            } else if (mUiStage.rightMode == RightButtonMode.Confirm) {
                if (mUiStage != Stage.ChoiceConfirmed) {
                    throw new IllegalStateException("expected ui stage " + Stage.ChoiceConfirmed
                            + " when button is " + RightButtonMode.Confirm);
                }
                startSaveAndFinish();
            } else if (mUiStage.rightMode == RightButtonMode.Ok) {
                ......
            }
        }

可以看到此时调用startSaveAndFinish();来保存图案,方法如下:

// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/
// /settings/password/ChooseLockPattern.java/ChooseLockPatternFragment
private void startSaveAndFinish() {
            if (mSaveAndFinishWorker != null) {
                Log.w(TAG, "startSaveAndFinish with an existing SaveAndFinishWorker.");
                return;
            }

            setRightButtonEnabled(false);

            mSaveAndFinishWorker = new SaveAndFinishWorker();
            mSaveAndFinishWorker.setListener(this);

            getFragmentManager().beginTransaction().add(mSaveAndFinishWorker,
                    FRAGMENT_TAG_SAVE_AND_FINISH).commit();
            getFragmentManager().executePendingTransactions();

            final boolean required = getActivity().getIntent().getBooleanExtra(
                    EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
            mSaveAndFinishWorker.start(mChooseLockSettingsHelper.utils(), required,
                    mHasChallenge, mChallenge, mChosenPattern, mCurrentPattern, mUserId);
        }

首先为mSaveAndFinishWorker设置了一个监听器,接着调用mSaveAndFinishWorker.start开启一个AsyncTask异步线程,在子线程中调用saveAndVerifyInBackground()用来保存图案设置并返回一个intent,结束后触发监听器(mFinished = true;)然后调用startActivity(intent) 跳转到RedactionInterstitial.java,此时页面为如下截图:
Setting 选择密码解析(一)_第10张图片

你可能感兴趣的:(Android,源码)