什麼是確認密碼
人臉apk點擊開始錄入時,apk會通過Internt會調用ChooseLockGeneric.java,我們知道如果之前設置過密碼,再次進入時,則會依次跳轉到如下界面:
流程圖分析
首先看下整體的流程圖,有個大概瞭解:
確認密碼頁面前傳
整體結構
接着看下ChooseLockGeneric.java的整體結構如下:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/
//com/android/settings/password/ChooseLockGeneric.java
public class ChooseLockGeneric extends SettingsActivity {
public static final String CONFIRM_CREDENTIALS = "confirm_credentials";
public static class ChooseLockGenericFragment extends SettingsPreferenceFragment{}
}
可以看到,ChooseLockGeneric繼承自SettingsActivity,所以我們從SettingsActivity 的onCreat()方法入手,log打印如下:
頁面流程分析
首先看chooseLockGenericFragment的onCreat流程,如下所示
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ChooseLockGeneric.java/ChooseLockGenericFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Activity activity = getActivity();
......
//FACE_UNLOCK_SUPPORT start
if (isFaceUnlockSupport()) {
mVerifyUnlock = getActivity().getIntent().getBooleanExtra("verify_unlock", false);
Log.d(TAG, "onCreate mVerifyUnlock = " + mVerifyUnlock);
}
//FACE_UNLOCK_SUPPORT end
.........
//第一次進入時mPasswordConfirmed、mWaitingForConfirmation都被初始化爲false
if (mPasswordConfirmed) {
updatePreferencesOrFinish(savedInstanceState != null);
if (mForChangeCredRequiredForBoot) {
maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
mUserId), false);
}
} else if (!mWaitingForConfirmation) {//會走着個流程
//初始化ChooseLockSettingsHelper,this指的是Fragment即ChooseLockGenericFragment
ChooseLockSettingsHelper helper =
new ChooseLockSettingsHelper(this.getActivity(), this);
boolean managedProfileWithUnifiedLock =
UserManager.get(getActivity()).isManagedProfile(mUserId)
&& !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
//log打印managedProfileWithUnifiedLock和skipConfirmation 都爲false
if (skipConfirmation
|| !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
//發現並沒有進入這個流程說明helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
//getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)返回true
mPasswordConfirmed = true; // no password set, so no need to confirm
//此時savedInstanceState爲null
updatePreferencesOrFinish(savedInstanceState != null);
} else {
mWaitingForConfirmation = true;
}
}
addHeaderView();
}
我們來看下helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)方法幹了些什麼,跟蹤發現最後調用到如下方法:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ChooseLockSettingsHelper.java
private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
@Nullable CharSequence header, @Nullable CharSequence description,
boolean returnCredentials, boolean external, boolean hasChallenge,
long challenge, int userId, @Nullable CharSequence alternateButton, Bundle extras) {
final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
boolean launched = false;
Log.d(TAG,"ChooseLockSettingsHelper launchConfirmationActivity request"+ ":title: "+title+" :header: "+header
+" :description: "+description+" :returnCredentials: "+returnCredentials+" :external: "+external
+" :hasChallenge: "+hasChallenge);
//Log打印如下:ChooseLockSettingsHelper launchConfirmationActivity request:title: 屏幕鎖定 :header: null
//:description: null :returnCredentials: true :external: false :hasChallenge: false
switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING://圖案
//log打印爲65536,爲圖案,由上面的log可以看出returnCredentials爲true,所以爲ConfirmLockPattern.InternalActivity.class
//所以會執行如下方法
launched = launchConfirmationActivity(request, title, header, description,
returnCredentials || hasChallenge
? ConfirmLockPattern.InternalActivity.class
: ConfirmLockPattern.class, returnCredentials, external,
hasChallenge, challenge, userId, alternateButton, extras);
break;
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX://PIN碼
case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX://密碼
case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
......
break;
}
return launched;
}
其中幾種鎖屏方式如下:
public enum ScreenLockType {
NONE(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
"unlock_set_off"), //無
SWIPE(
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
"unlock_set_none"),//滑動
PATTERN(
DevicePolicyManager.PASSWORD_QUALITY_SOMETHING,
"unlock_set_pattern"),//圖案
PIN(
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC,//默認,低優先級
DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX,//高優先級
"unlock_set_pin"),//PIN
PASSWORD(
DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,//默認,低優先級
DevicePolicyManager.PASSWORD_QUALITY_COMPLEX,//高優先級
"unlock_set_password"),//密碼
MANAGED(
DevicePolicyManager.PASSWORD_QUALITY_MANAGED,
"unlock_set_managed");
}
接着我們來看case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:裏面執行的launchConfirmationActivity,方法如下:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ChooseLockSettingsHelper.java
private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
CharSequence message, Class<?> activityClass, boolean returnCredentials,
boolean external, boolean hasChallenge, long challenge,
int userId, @Nullable CharSequence alternateButton, Bundle extras) {
final Intent intent = new Intent();
//爲intent設置一些參數
......
//由上面log分析可知,此時的activityClass.getName()爲ConfirmLockPattern.java
//裏的一個空的靜態內部類InternalActivity
intent.setClassName(ConfirmDeviceCredentialBaseFragment.PACKAGE, activityClass.getName());
//由上面打印的log可以看出external爲false
if (external) {
......
} else {
//此mFragment爲ChooseLockGenericFragment的onCreate方法中初始化的ChooseLockSettingsHelper裏的Fragment
//此時不爲null
if (mFragment != null) {
//爲intent設置theme
copyInternalExtras(mFragment.getActivity().getIntent(), intent);
//啓動intent,即跳轉到ConfirmLockPattern.java
mFragment.startActivityForResult(intent, request);
} else {
......
}
}
return true;
}
此時通過調用mFragment.startActivityForResult(intent, request);方法跳轉到ConfirmLockPattern.java,即如下界面:
確認密碼頁面分析
整體結構
接下來我們來看下ConfirmLockPattern.java的結構
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ConfirmLockPattern.java
public class ConfirmLockPattern extends ConfirmDeviceCredentialBaseActivity {
public static class InternalActivity extends ConfirmLockPattern {}
public static class ConfirmLockPatternFragment extends ConfirmDeviceCredentialBaseFragment
implements AppearAnimationCreator<Object>, CredentialCheckResultTracker.Listener{}
}
ConfirmDeviceCredentialBaseActivity.java結構如下:
public abstract class ConfirmDeviceCredentialBaseActivity extends SettingsActivity {}
所以啓動跳轉到ConfirmLockPattern.java的SettingsActivity打印log如下:
頁面流程分析
接着來看ConfirmLockPatternFragment的onCreateView方法,如下所示:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ConfirmLockPattern.java/ConfirmLockPatternFragment
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//加載佈局、設置view id、處理點擊事件
......
//獲取intent,由上面log可知mHeaderText、mDetailsText都爲null
Intent intent = getActivity().getIntent();
if (intent != null) {
mHeaderText = intent.getCharSequenceExtra(
ConfirmDeviceCredentialBaseFragment.HEADER_TEXT);
mDetailsText = intent.getCharSequenceExtra(
ConfirmDeviceCredentialBaseFragment.DETAILS_TEXT);
}
//設置一些監聽事件
......
//更新狀態
updateStage(Stage.NeedToUnlock);
......
return view;
}
接着我們來看下updateStage(Stage.NeedToUnlock);方法如下:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ConfirmLockPattern.java/ConfirmLockPatternFragment
private void updateStage(Stage stage) {
switch (stage) {
case NeedToUnlock:
if (mHeaderText != null) {
mHeaderTextView.setText(mHeaderText);
} else {
//mHeaderText爲null,會執行這裏
//getDefaultHeader()返回字符串:"確認您的圖案"
mHeaderTextView.setText(getDefaultHeader());
}
if (mDetailsText != null) {
mDetailsTextView.setText(mDetailsText);
} else {
//mDetailsText爲null,會執行這裏
//getDefaultDetails()返回字符串:"請繪製您的設備解鎖圖案以繼續"
mDetailsTextView.setText(getDefaultDetails());
}
mErrorTextView.setText("");
updateErrorMessage(
mLockPatternUtils.getCurrentFailedPasswordAttempts(mEffectiveUserId));
mLockPatternView.setEnabled(true);
mLockPatternView.enableInput();
mLockPatternView.clearPattern();
break;
......
}
}
接着會執行onResume(),設置監聽事件mCredentialCheckResultTracker.setListener(this);來監聽判斷圖案繪製。
我們可以從ChooseLockSettingsHelper.java中的launchConfirmationActivity方法中可以看出最後結果是 return true,所以回到ChooseLockGeneric.java,發現最後會執行到如下:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ChooseLockGeneric.java/ChooseLockGenericFragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
......
//打印log發現第一次時mPasswordConfirmed、mWaitingForConfirmation都爲false
if (mPasswordConfirmed) {
......
} else if (!mWaitingForConfirmation) {//會走着個流程
......
//log打印managedProfileWithUnifiedLock和skipConfirmation 都爲false
if (skipConfirmation
|| !helper.launchConfirmationActivity(CONFIRM_EXISTING_REQUEST,
getString(R.string.unlock_set_unlock_launch_picker_title), true, mUserId)) {
......
} else {
//此時會執行到這裏
mWaitingForConfirmation = true;
}
}
addHeaderView();
}
繪製完成,結束頁面
當繪製完密碼後,會執行onActivityResult方法,如下所示:
// /vendor/mediatek/proprietary/package/apps/MTKSettings/src/com/android/settings
// /password/ChooseLockGeneric.java/ChooseLockGenericFragment
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG,"onActivityResult");
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG,"onActivityResult1 requestCode:resultCode "+requestCode+" : "+resultCode +" :data: "+ data);
mWaitingForConfirmation = false;
if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
Log.d(TAG,"onActivityResult2");
//FACE_UNLOCK_SUPPORT start
if (isFaceUnlockSupport() && mVerifyUnlock) {
data.putExtra("mVerify", true);
getActivity().setResult(resultCode, data);
finish();
} else {
//FACE_UNLOCK_SUPPORT end
......
//FACE_UNLOCK_SUPPORT start
}
//FACE_UNLOCK_SUPPORT end
}
......
}
打印log如下:
其中requestCode 100即爲CONFIRM_EXISTING_REQUEST,此時如果含有人臉的話會結束掉此密碼驗證頁面,進入到開始錄入界面,即下圖所示: