選擇解鎖方式頁面的加載
首先還是從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 */);
}
}
此時佈局已經加載完成,界面截圖如下:
選擇解鎖方式
當選擇解鎖方式時,點擊任意一種都會執行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,頁面截圖如下:
接着上面來看,由於EncryptionInterstitial繼承SettingsActivity,所以打印log如下:
所以下面我們來看看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進行圖案密碼的輸入,頁面截圖如下:
圖案密碼輸入頁面
我們首先看下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);方法,看下第一次繪製時會執行什麼,截圖如下:
方法如下:
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<LockPatternView.Cell> 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<LockPatternView.Cell>(pattern);
updateStage(Stage.FirstChoiceValid);
}
} else {
throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
+ "entering the pattern.");
}
}
public void onPatternCellAdded(List<Cell> 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,繪製過程中界面如下:
當繪製完成時,調用onPatternDetected,我們看下第一次繪製完成,此方法做了什麼,方法如下:
protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
new LockPatternView.OnPatternListener() {
......
//圖案繪製完成時調用
public void onPatternDetected(List<LockPatternView.Cell> 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<LockPatternView.Cell>(pattern);
updateStage(Stage.FirstChoiceValid);
}
} else {
throw new IllegalStateException("Unexpected stage " + mUiStage + " when "
+ "entering the pattern.");
}
}
......
};
接着調用updateStage(Stage.FirstChoiceValid);即上面的方法,可以看到,此時updateStage方法僅僅是做了一些更新UI的操作,比如設置buttun的狀態和字體以及header的文字等,我們可以看下此時的頁面,頁面如下:
此時狀態爲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,讓用戶重新繪製。此時用戶界面爲:
當第二次繪製完成時,此時會再調用onPatternDetected,我們來看下此時的方法,方法如下:
public void onPatternDetected(List<LockPatternView.Cell> 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,我們看下當兩次繪製圖案一樣時,此時用戶界面是什麼,截圖如下:
疑問:兩次繪製的密碼是怎麼保存的?
我們來看下當第一次繪製完密碼時,調用onPatternDetected,我們看下此時代碼:
public void onPatternDetected(List<LockPatternView.Cell> 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<LockPatternView.Cell>(pattern);
updateStage(Stage.FirstChoiceValid);
}
} else {
......
}
}
可以看到此時會新建一個ArrayList將第一次繪製完成的pattern保存到此mChosenPattern,用來做第二次繪製完成密碼時的判斷,即
protected LockPatternView.OnPatternListener mChooseNewLockPatternListener =
new LockPatternView.OnPatternListener() {
public void onPatternDetected(List<LockPatternView.Cell> 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,此時頁面爲如下截圖: