android13#settings#security

294 阅读15分钟

1.简介

  • 主要学习下screen lock 页面的逻辑,lock方式的切换,验证逻辑
  • 看下密码相关的数据获取以及存储逻辑
    <com.android.settings.widget.HomepagePreference
        android:fragment="com.android.settings.security.SecuritySettings"
        android:icon="@drawable/ic_settings_security_white"
        android:key="top_level_security"
        android:order="-50"
        android:title="@string/security_settings_title"
        android:summary="@string/security_dashboard_summary"
        settings:highlightableMenuKey="@string/menu_key_security"
        settings:controller="com.android.settings.security.TopLevelSecurityEntryPreferenceController"/>

1.1.图片

image.png

2.SecuritySettings

image.png

2.1.security_dashboard_settings.xml

<PreferenceScreen
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:settings="http://schemas.android.com/apk/res-auto"
    android:key="security_dashboard_page"
    android:title="@string/security_settings_title">

    <!-- security_settings_status.xml -->
    <PreferenceCategory
        android:order="-10"
        android:key="security_status"
        android:title="@string/security_status_title" />

    <PreferenceCategory
        android:order="1"
        android:key="dashboard_tile_placeholder" />

    <!-- security section 里边有4种,后3种根据设备是否支持来决定显示与否-->
    <PreferenceCategory
        android:order="10"
        android:key="security_category"
        android:title="@string/lock_settings_title">
        <!--常见的上划,密码,PIN码,图案等-->
        <com.android.settings.widget.GearPreference
            android:key="unlock_set_or_change"
            android:title="@string/unlock_set_unlock_launch_picker_title"
            android:summary="@string/summary_placeholder"
            settings:keywords="@string/keywords_lockscreen" />
        <!--指纹识别-->
        <com.android.settingslib.RestrictedPreference
            android:key="fingerprint_settings"
            android:title="@string/security_settings_fingerprint_preference_title"
            android:summary="@string/summary_placeholder"
            settings:keywords="@string/keywords_fingerprint_settings" />
        <!--人脸识别-->
        <com.android.settingslib.RestrictedPreference
            android:key="face_settings"
            android:title="@string/security_settings_face_preference_title"
            android:summary="@string/summary_placeholder"
            settings:keywords="@string/keywords_face_settings" />
        <!--生物识别,包括指纹和人脸-->
        <com.android.settingslib.RestrictedPreference
            android:key="biometric_settings"
            android:title="@string/security_settings_biometric_preference_title"
            android:summary="@string/summary_placeholder"
            settings:keywords="@string/keywords_biometric_settings" />
    </PreferenceCategory>

    <!--更多安全设置-->
    <Preference
        android:order="100"
        android:key="security_advanced_settings"
        android:title="@string/security_advanced_settings"
        android:summary="@string/summary_placeholder"
        android:fragment="com.android.settings.security.SecurityAdvancedSettings"
        settings:controller="com.android.settings.security.SecurityAdvancedSettingsController"
        settings:keywords="@string/security_advanced_settings_keywords" />

</PreferenceScreen>

2.2.buildPreferenceControllers

控制器都在这里了,我们只研究下默认的

    private static List<AbstractPreferenceController> buildPreferenceControllers
    (Context context,
            Lifecycle lifecycle, SecuritySettings host) {
        final List<AbstractPreferenceController> controllers = new ArrayList<>();
        //这是4种安全锁对应的controller
        final List<AbstractPreferenceController> securityPreferenceControllers = new ArrayList<>();
        //人脸识别的
        securityPreferenceControllers.add(new FaceStatusPreferenceController(context, lifecycle));
        //指纹识别的
        securityPreferenceControllers.add(new FingerprintStatusPreferenceController(
                context, lifecycle));
        //生物识别的
        securityPreferenceControllers.add(new CombinedBiometricStatusPreferenceController(
                context, lifecycle));
        //默认的,具体见小节3
        securityPreferenceControllers.add(new ChangeScreenLockPreferenceController(context, host));
        //这是4种锁外边的容器security_category的控制器
        controllers.add(new PreferenceCategoryController(context, SECURITY_CATEGORY)
                .setChildren(securityPreferenceControllers));
        controllers.addAll(securityPreferenceControllers);

        return controllers;
    }

3.ChangeScreenLockPreferenceController

这个控制器控制的就是下图这个选项的内容,完整的页面图见小节2

  • none或者swipe的时候显示如下,没有齿轮 image.png
  • password,pin, pattern的时候显示如下,带齿轮: image.png

3.1.isAvailable

控制选项是否可用,默认是true

    public boolean isAvailable() {
        return mScreenLockPreferenceDetailUtils.isAvailable();//见 4.1
    }

3.2.updateState

是否显示齿轮菜单,就是下图这个,非swipe或者none的时候会显示

    public void updateState(Preference preference) {
        if (mPreference != null && mPreference instanceof GearPreference) {
            //见4.2,根据lock类型决定是否需要显示齿轮按钮
            if (mScreenLockPreferenceDetailUtils.shouldShowGearMenu()) {
            //需要显示齿轮菜单,给齿轮设置点击事件跳转,listener不为空,齿轮显示
                ((GearPreference) mPreference).setOnGearClickListener(this);//点击事件见补充1
            } else {
                //listener为null,齿轮隐藏
                ((GearPreference) mPreference).setOnGearClickListener(null);
            }
        }
        //见补充2,获取摘要
        updateSummary(preference, mUserId);
        disableIfPasswordQualityManaged(mUserId);
        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)) {
            disableIfPasswordQualityManaged(mProfileChallengeUserId);
        }
    }

>1.onGearClick

齿轮点击跳转的逻辑,工具类处理的,见4.3

    public void onGearClick(GearPreference p) {
        if (TextUtils.equals(p.getKey(), getPreferenceKey())) { 
        //见4.3
        mScreenLockPreferenceDetailUtils.openScreenLockSettings(mHost.getMetricsCategory());
        }
    }

>2.updateSummary

    protected void updateSummary(Preference preference, int userId) {
        preference.setSummary(mScreenLockPreferenceDetailUtils.getSummary(userId));//见4.4
        mPreference.setEnabled(true);
    }

3.3.handlePreferenceTreeClick

这个是整个选项点击后的跳转逻辑

    public boolean handlePreferenceTreeClick(Preference preference) {
        if (!TextUtils.equals(preference.getKey(), getPreferenceKey())) {
            return super.handlePreferenceTreeClick(preference);
        }
        //见4.5,最终跳转的页面是小节8
        return mScreenLockPreferenceDetailUtils.openChooseLockGenericFragment(
                mHost.getMetricsCategory());
    }

4.ScreenLockPreferenceDetailsUtils

4.1.isAvailable

默认是true

    public boolean isAvailable() {
        return mContext.getResources().getBoolean(R.bool.config_show_unlock_set_or_change);
    }

4.2.shouldShowGearMenu

是否应该显示齿轮按钮,none或者swipe不显示,其他的比如password,pin,pattern需要显示

    public boolean shouldShowGearMenu() {
        return isLockPatternSecure();
    }

    public boolean isLockPatternSecure() {
    //见小节5.1
        return mLockPatternUtils.isSecure(mUserId);
    }

4.3.openScreenLockSettings

齿轮按钮点击跳转到如下的页面

image.png

    public void openScreenLockSettings(int sourceMetricsCategory) {
        mContext.startActivity(getLaunchScreenLockSettingsIntent(sourceMetricsCategory));
    }

>1.getLaunchScreenLockSettingsIntent

    public Intent getLaunchScreenLockSettingsIntent(int sourceMetricsCategory) {
        return new SubSettingLauncher(mContext)
                .setDestination(ScreenLockSettings.class.getName())
                .setSourceMetricsCategory(sourceMetricsCategory)
                .toIntent();
    }

4.4.getSummary

    public String getSummary(int userId) {
            //见补充1
        final Integer summaryResId = getSummaryResId(userId);
        return summaryResId != null ? mContext.getResources().getString(summaryResId) : null;
    }

>1.getSummaryResId

根据当前的锁屏类型,返回对应的摘要字符串id

    private Integer getSummaryResId(int userId) {
        //非安全模式,也就是none或者swipe
        if (!mLockPatternUtils.isSecure(userId)) {
            if (userId == mProfileChallengeUserId
                //见5.7
                    || mLockPatternUtils.isLockScreenDisabled(userId)) {
                return R.string.unlock_set_unlock_mode_off; //none
            } else {
                return R.string.unlock_set_unlock_mode_none;//swipe
            }
        } else {
            //见5.10
            int keyguardStoredPasswordQuality =
                    mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
            switch (keyguardStoredPasswordQuality) {
                case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
                    return R.string.unlock_set_unlock_mode_pattern;
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
                    return R.string.unlock_set_unlock_mode_pin;
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
                case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
                case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
                case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
                    return R.string.unlock_set_unlock_mode_password;
                default:
                    return null;
            }
        }
    }

4.5.openChooseLockGenericFragment

选项点击跳转如下页面

    public boolean openChooseLockGenericFragment(int sourceMetricsCategory) {
        final Intent quietModeDialogIntent = getQuietModeDialogIntent();
        if (quietModeDialogIntent != null) {
            mContext.startActivity(quietModeDialogIntent);
            return false;
        }
        //正常走这里,intent见补充2
        mContext.startActivity(getChooseLockGenericFragmentIntent(sourceMetricsCategory));
        return true;
    }

>1.getQuietModeDialogIntent

正常返回空

    private Intent getQuietModeDialogIntent() {
        if (mProfileChallengeUserId != UserHandle.USER_NULL
                && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mProfileChallengeUserId)
                && StorageManager.isFileEncryptedNativeOnly()) {
            if (mUm.isQuietModeEnabled(UserHandle.of(mProfileChallengeUserId))) {
                return UnlaunchableAppActivity.createInQuietModeDialogIntent(
                        mProfileChallengeUserId);
            }
        }
        return null;
    }

>2.getChooseLockGenericFragmentIntent

跳转页面ChooseLockGenericFragment,见小节8

    private Intent getChooseLockGenericFragmentIntent(int sourceMetricsCategory) {
        return new SubSettingLauncher(mContext)
                .setDestination(ChooseLockGenericFragment.class.getName())
                .setSourceMetricsCategory(sourceMetricsCategory)
                .setTransitionType(SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE)
                .toIntent();
    }

5.LockPatternUtils.java

5.1.isSecure

凭据类型不是none(也就是设置了Pattern,PIN或者password),那么就说明设置了凭据

    public boolean isSecure(int userId) {
        int type = getCredentialTypeForUser(userId);
        return type != CREDENTIAL_TYPE_NONE;
    }

5.2.getCredentialTypeForUser

获取凭据的类型

    public @CredentialType int getCredentialTypeForUser(int userHandle) {
    //见5.3
        return mCredentialTypeCache.query(userHandle);
    }

>1.CredentialType

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(prefix = {"CREDENTIAL_TYPE_"}, value = {
            CREDENTIAL_TYPE_NONE, //-1
            CREDENTIAL_TYPE_PATTERN, //1
            CREDENTIAL_TYPE_PASSWORD, //4
            CREDENTIAL_TYPE_PIN, //3
            // CREDENTIAL_TYPE_PASSWORD_OR_PIN is missing on purpose.
    })
    public @interface CredentialType {}

5.3.mCredentialTypeCache

    private final static String CREDENTIAL_TYPE_API = "getCredentialType";
    /**
     * Special user id for triggering the FRP verification flow.
     */
    public static final int USER_FRP = UserHandle.USER_NULL + 1;//-10000+1    
    
    private final PropertyInvalidatedCache<Integer, Integer> mCredentialTypeCache =
            new PropertyInvalidatedCache<>(4, PropertyInvalidatedCache.MODULE_SYSTEM,
                    CREDENTIAL_TYPE_API, CREDENTIAL_TYPE_API, mCredentialTypeQuery);
    //查询方法就是这个
    private final PropertyInvalidatedCache.QueryHandler<Integer, Integer> mCredentialTypeQuery =
            new PropertyInvalidatedCache.QueryHandler<>() {
                @Override
                public Integer apply(Integer userHandle) {
                    try {
                    //见5.4
                        return getLockSettings().getCredentialType(userHandle);
                    } catch (RemoteException re) {
                        return CREDENTIAL_TYPE_NONE;
                    }
                }
                @Override
                public boolean shouldBypassCache(Integer userHandle) {
                //返回ture表示绕过缓存
                    return userHandle == USER_FRP;
                }
            };

//
    public ILockSettings getLockSettings() {
        if (mLockSettingsService == null) {
        //见5.4
            ILockSettings service = ILockSettings.Stub.asInterface(
                    ServiceManager.getService("lock_settings"));
            mLockSettingsService = service;
        }
        return mLockSettingsService;
    }

5.4.LockSettingsService.java

    public int getCredentialType(int userId) {
        checkPasswordHavePermission(userId);
        return getCredentialTypeInternal(userId);
    }

    public int getCredentialTypeInternal(int userId) {
        if (userId == USER_FRP) {
            return getFrpCredentialType();
        }
        synchronized (mSpManager) {
            //见补充1,读取数据库,看有没有对应的handle
            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
                //获取handle,数据库里的值
                final long handle = getSyntheticPasswordHandleLocked(userId);
                //见小节7.1,根据handle读取对应的文件,解析内容返回type
                int rawType = mSpManager.getCredentialType(handle, userId);
                if (rawType != CREDENTIAL_TYPE_PASSWORD_OR_PIN) {
                    return rawType;
                }
                //CREDENTIAL_TYPE_PASSWORD_OR_PIN 这种是遗留的,所以特殊处理下
                //见补充2和3
                return pinOrPasswordQualityToCredentialType(getKeyguardStoredQuality(userId));
            }
        }
        // Intentional duplication of the getKeyguardStoredQuality() call above since this is a
        // unlikely code path (device with pre-synthetic password credential). We want to skip
        // calling getKeyguardStoredQuality whenever possible.
        //补充2
        final int savedQuality = getKeyguardStoredQuality(userId);
        if (savedQuality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING //0x10000;
                //见6.3
                && mStorage.hasPattern(userId)) {
            return CREDENTIAL_TYPE_PATTERN;
        }
        if (savedQuality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC //0x20000;
                && mStorage.hasPassword(userId)) {
        //见补充3
            return pinOrPasswordQualityToCredentialType(savedQuality);
        }
        return CREDENTIAL_TYPE_NONE;
    }

>1.isSyntheticPasswordBasedCredentialLocked

    private boolean isSyntheticPasswordBasedCredentialLocked(int userId) {
        if (userId == USER_FRP) {
            final int type = mStorage.readPersistentDataBlock().type;
            return type == PersistentData.TYPE_SP || type == PersistentData.TYPE_SP_WEAVER;
        }
        long handle = getSyntheticPasswordHandleLocked(userId);
        return handle != SyntheticPasswordManager.DEFAULT_HANDLE;
    }
    //具体就是6.2里的数据库
    long getSyntheticPasswordHandleLocked(int userId) {
        return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY,
                SyntheticPasswordManager.DEFAULT_HANDLE, userId);
    }

>2.getKeyguardStoredQuality

最终读取的是6.2里的数据库里的值

    private int getKeyguardStoredQuality(int userId) {
        return (int) mStorage.getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
                DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userId);
    }

>3.pinOrPasswordQualityToCredentialType

    private static int pinOrPasswordQualityToCredentialType(int quality) {
        //见5.5
        if (LockPatternUtils.isQualityAlphabeticPassword(quality)) {
            return CREDENTIAL_TYPE_PASSWORD;
        }
        //见5.6
        if (LockPatternUtils.isQualityNumericPin(quality)) {
            return CREDENTIAL_TYPE_PIN;
        }
        throw new IllegalArgumentException("Quality is neither Pin nor password: " + quality);
    }

5.5.isQualityAlphabeticPassword

    public static boolean isQualityAlphabeticPassword(int quality) {
        return quality >= PASSWORD_QUALITY_ALPHABETIC;//0x40000;
    }

5.6.isQualityNumericPin

    public static boolean isQualityNumericPin(int quality) {
    //0x20000;  0x30000;
        return quality == PASSWORD_QUALITY_NUMERIC || quality == PASSWORD_QUALITY_NUMERIC_COMPLEX;
    }

5.7.isLockScreenDisabled

    public boolean isLockScreenDisabled(int userId) {
        if (isSecure(userId)) {
        //安全模式下肯定是false了
            return false;
        }
        boolean disabledByDefault = mContext.getResources().getBoolean(
                com.android.internal.R.bool.config_disableLockscreenByDefault);
        boolean isSystemUser = UserManager.isSplitSystemUser() && userId == UserHandle.USER_SYSTEM;
        UserInfo userInfo = getUserManager().getUserInfo(userId);
        boolean isDemoUser = UserManager.isDeviceInDemoMode(mContext) && userInfo != null
                && userInfo.isDemo();
    //1.读取  DISABLE_LOCKSCREEN_KEY 的值,这个是数据库里的 
    //2.配置里默认disable为true并且非系统用户
    //3.测试用户
        return getBoolean(DISABLE_LOCKSCREEN_KEY, false, userId)
                || (disabledByDefault && !isSystemUser)
                || isDemoUser;
    }

>1.disabledByDefault

新用户是否默认禁止掉锁屏,默认值false

    <!-- Is the lock-screen disabled for new users by default -->
    <bool name="config_disableLockscreenByDefault">false</bool>

5.8.hasSecureLockScreen

    public boolean hasSecureLockScreen() {
        if (mHasSecureLockScreen == null) {
            try {
                mHasSecureLockScreen = Boolean.valueOf(getLockSettings().hasSecureLockScreen());
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
        }
        return mHasSecureLockScreen.booleanValue();
    }

其实最终读取的是LockSettingsService里的值,看是否有对应的feature

   
        mHasSecureLockScreen = mContext.getPackageManager()
                .hasSystemFeature(PackageManager.FEATURE_SECURE_LOCK_SCREEN);

5.9.setLockScreenDisabled

这个最终是写到数据库里的,就是5.7里用的

    public void setLockScreenDisabled(boolean disable, int userId) {
        setBoolean(DISABLE_LOCKSCREEN_KEY, disable, userId);
    }

5.10.getKeyguardStoredPasswordQuality

    public int getKeyguardStoredPasswordQuality(int userHandle) {
    //type获取见5.2
        return credentialTypeToPasswordQuality(getCredentialTypeForUser(userHandle));
    }

>1.credentialTypeToPasswordQuality

凭据类型转化为quality值

    public static int credentialTypeToPasswordQuality(int credentialType) {
        switch (credentialType) {
            case CREDENTIAL_TYPE_NONE:
                return PASSWORD_QUALITY_UNSPECIFIED;
            case CREDENTIAL_TYPE_PATTERN:
                return PASSWORD_QUALITY_SOMETHING;
            case CREDENTIAL_TYPE_PIN:
                return PASSWORD_QUALITY_NUMERIC;
            case CREDENTIAL_TYPE_PASSWORD:
                return PASSWORD_QUALITY_ALPHABETIC;
            default:
                throw new IllegalStateException("Unknown type: " + credentialType);
        }
    }

5.11.isCredentialsDisabledForUser

是否允许用户通过PASSWORD_QUALITY_MANAGED设置任何凭据

    public boolean isCredentialsDisabledForUser(int userId) {
        return getDevicePolicyManager().getPasswordQuality(/* admin= */ null, userId)
                == PASSWORD_QUALITY_MANAGED;
    }

6.LockSettingsStorage.java

6.1.readSyntheticPasswordState

    public byte[] readSyntheticPasswordState(int userId, long handle, String name) {
        return readFile(getSynthenticPasswordStateFilePathForUser(userId, handle, name));
    }

>1.getSynthenticPasswordStateFilePathForUser

    protected String getSynthenticPasswordStateFilePathForUser(int userId, long handle,
            String name) {
            //目录见补充2
        final File baseDir = getSyntheticPasswordDirectoryForUser(userId);
        //文件名字就是handle的十六进制加上点name
        final String baseName = formatSimple("%016x.%s", handle, name);
        return new File(baseDir, baseName).getAbsolutePath();
    }

>2.getSyntheticPasswordDirectoryForUser

返回目录 /data/system_de/0/spblob/

    private static final String SYNTHETIC_PASSWORD_DIRECTORY = "spblob/";
    protected File getSyntheticPasswordDirectoryForUser(int userId) {
        return new File(Environment.getDataSystemDeDirectory(userId) ,SYNTHETIC_PASSWORD_DIRECTORY);
    }

存储目录/data/system_de/0/

    public static File getDataSystemDeDirectory(int userId) {
        return buildPath(getDataDirectory(), "system_de", String.valueOf(userId));
    }

6.2.数据库

数据是从数据库里读出来的

    private static final String DATABASE_NAME = "locksettings.db";
    private static final String TABLE = "locksettings";       
    private static final String COLUMN_KEY = "name";
    private static final String COLUMN_USERID = "user";
    private static final String COLUMN_VALUE = "value";
    //存储表信息如下
    private void createTable(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + TABLE + " (" +
                    "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
                    COLUMN_KEY + " TEXT," +
                    COLUMN_USERID + " INTEGER," +
                    COLUMN_VALUE + " TEXT" +
                    ");");
        }
 //这是读取数据的代码,根据user以及key查询value
        Object result = DEFAULT;
        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        if ((cursor = db.query(TABLE, COLUMNS_FOR_QUERY,
                COLUMN_USERID + "=? AND " + COLUMN_KEY + "=?",
                new String[] { Integer.toString(userId), key },
                null, null, null)) != null) {
            if (cursor.moveToFirst()) {
                result = cursor.getString(0);
            }
            cursor.close();
        }

6.3.hasPassword

获取补充2里的路径下的gatekeeper.password.key文件内容是否为空

    public boolean hasPassword(int userId) {
        return hasFile(getLockPasswordFilename(userId));
    }

>1.getLockPasswordFilename

    private static final String LOCK_PASSWORD_FILE = "gatekeeper.password.key文件内容是否为空";
    String getLockPasswordFilename(int userId) {
        return getLockCredentialFilePathForUser(userId, LOCK_PASSWORD_FILE);
    }

>2.getLockCredentialFilePathForUser

  • userid是0 路径是: /data/system/0
  • userid不是0,路径是: /data/system/users/xxx
    private static final String SYSTEM_DIRECTORY = "/system/";
    private String getLockCredentialFilePathForUser(int userId, String basename) {
        String dataSystemDirectory = Environment.getDataDirectory().getAbsolutePath() +
                        SYSTEM_DIRECTORY;
        if (userId == 0) {
            // Leave it in the same place for user 0
            return dataSystemDirectory + basename;
        } else {
            return new File(Environment.getUserSystemDirectory(userId), basename).getAbsolutePath();
        }
    }

7.SyntheticPasswordManager.java

7.1.getCredentialType

    private static final String PASSWORD_DATA_NAME = "pwd";
    int getCredentialType(long handle, int userId) {
        //见7.2,从文件读取数据,handle决定了文件的名字
        byte[] passwordData = loadState(PASSWORD_DATA_NAME, handle, userId);
        if (passwordData == null) {
            return LockPatternUtils.CREDENTIAL_TYPE_NONE;
        }
        //解析读取的byte数组,封装成对象,获取type返回
        return PasswordData.fromBytes(passwordData).credentialType;
    }

7.2.loadState

    private byte[] loadState(String stateName, long handle, int userId) {
    //见6.1
        return mStorage.readSyntheticPasswordState(userId, handle, stateName);
    }

8.ChooseLockGenericFragment

    public static class ChooseLockGenericFragment extends SettingsPreferenceFragment {

image.png

8.1.security_settings_picker.xml

根据条件显示不同的选项

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:settings="http://schemas.android.com/apk/res-auto"
        android:key="lock_settings_picker">

<!--正常进来显示下边5个选项-->
    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_off"
            android:title="@string/unlock_set_unlock_off_title"
            android:icon="@drawable/ic_lock_none"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_none"
            android:title="@string/unlock_set_unlock_none_title"
            android:icon="@drawable/ic_lock_swipe"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_pattern"
            android:title="@string/unlock_set_unlock_pattern_title"
            android:icon="@drawable/ic_pattern"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_pin"
            android:title="@string/unlock_set_unlock_pin_title"
            android:icon="@drawable/ic_lock_pin"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_password"
            android:title="@string/unlock_set_unlock_password_title"
            android:icon="@drawable/ic_password"
            android:persistent="false"/>

<!--下边是其他情况显示-->
    <com.android.settingslib.RestrictedPreference
            android:key="unlock_set_managed"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_skip_fingerprint"
            android:title="@string/fingerprint_unlock_skip_fingerprint"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
            android:key="unlock_skip_face"
            android:title="@string/face_unlock_skip_face"
            android:persistent="false"/>

    <com.android.settingslib.RestrictedPreference
        android:key="unlock_skip_biometrics"
        android:title="@string/biometrics_unlock_skip_biometrics"
        android:persistent="false"/>

    <com.android.settingslib.widget.FooterPreference
            android:key="lock_settings_footer"
            android:selectable="false"
            settings:searchable="false"/>

</PreferenceScreen>

8.2.onCreate

        public void onCreate(Bundle savedInstanceState) {
        //省略中间读值的逻辑
        //controller后边用
            mController = new ChooseLockGenericController.Builder(
                    getContext(), mUserId, mLockPatternUtils)
                    .setAppRequestedMinComplexity(mRequestedMinComplexity)
                    .setEnforceDevicePasswordRequirementOnly(mOnlyEnforceDevicePasswordRequirement)
                    .setProfileToUnify(mUnificationProfileId)
                    .setHideInsecureScreenLockTypes(alwaysHideInsecureScreenLockTypes()
                            || intent.getBooleanExtra(HIDE_INSECURE_OPTIONS, false))
                    .build();        
            //...
            if (mPasswordConfirmed) {
            //强制要求密码的走这里
                updatePreferencesOrFinish(savedInstanceState != null);
                if (mForChangeCredRequiredForBoot) {
                    maybeEnableEncryption(mLockPatternUtils.getKeyguardStoredPasswordQuality(
                            mUserId), false);
                }
            } else if (!mWaitingForConfirmation) {
                //正常走这里
                final ChooseLockSettingsHelper.Builder builder =
                        new ChooseLockSettingsHelper.Builder(activity, this);
                    //questCode
                builder.setRequestCode(CONFIRM_EXISTING_REQUEST)
                        .setTitle(getString(R.string.unlock_set_unlock_launch_picker_title))
                        .setReturnCredentials(true)
                        .setUserId(mUserId);
                boolean managedProfileWithUnifiedLock =
                        mIsManagedProfile
                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(mUserId);
                //不管这个,这个是管理类的程序控制的
                boolean skipConfirmation = managedProfileWithUnifiedLock && !mIsSetNewPassword;
        //比如设置了图案或者密码,那么正常会跳转到解锁密码或者图案页面,也就是下边的builder.show方法
        //show方法返回true表示进入了密码输入页面,返回false表示未进入密码页面,见9.1
                if (skipConfirmation || !builder.show()) {
                //走到这里说明没有密码或者不需要输入密码,显示正常的页面
                    mPasswordConfirmed = true; // no password set, so no need to confirm
                    //见8.4
                    updatePreferencesOrFinish(savedInstanceState != null);
                } else {
                    mWaitingForConfirmation = true;
                }
            }
            addHeaderView();
        }

8.3.onActivityResult

见9.3最后调用的这个fragment的startActivityForResult,这里就是回调

        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            super.onActivityResult(requestCode, resultCode, data);
            mWaitingForConfirmation = false;
            //requestCode见8.2 builder.setRequestCode方法
            if (requestCode == CONFIRM_EXISTING_REQUEST && resultCode == Activity.RESULT_OK) {
            //这里对应9.2从密码确认页面回来,
                mPasswordConfirmed = true;
                mUserPassword = data != null
                    ? data.getParcelableExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD)
                    : null;
                //见8.4
                updatePreferencesOrFinish(false /* isRecreatingActivity */);
                if (mForChangeCredRequiredForBoot) {
                    if (mUserPassword != null && !mUserPassword.isNone()) {
                        maybeEnableEncryption(
                                mLockPatternUtils.getKeyguardStoredPasswordQuality(mUserId), false);
                    } else {
                        finish();
                    }
                }

8.4.updatePreferencesOrFinish

更新选项或者关闭页面

        void updatePreferencesOrFinish(boolean isRecreatingActivity) {
            Intent intent = getActivity().getIntent();
            int quality = -1;
            if (StorageManager.isFileEncryptedNativeOrEmulated()) {
                quality = intent.getIntExtra(LockPatternUtils.PASSWORD_TYPE_KEY, -1);
            } 
            if (quality == -1) {
                // If caller didn't specify password quality, show UI and allow the user to choose.
                final PreferenceScreen prefScreen = getPreferenceScreen();
                if (prefScreen != null) {
                    prefScreen.removeAll();
                }
                addPreferences();//见补充1
                disableUnusablePreferences();//补充2
                updatePreferenceText();//补充4
                updateCurrentPreference();//补充5
            } else if (!isRecreatingActivity) {
                // Don't start the activity again if we are recreated for configuration change
                updateUnlockMethodAndFinish(quality, false, true /* chooseLockSkipped */);
            }
        }

>1.addPreferences

添加要显示的选项

        protected void addPreferences() {
        //从xml里获取
            addPreferencesFromResource(R.xml.security_settings_picker);

            int profileUserId = Utils.getManagedProfileId(mUserManager, mUserId);
            final FooterPreference footer = findPreference(KEY_LOCK_SETTINGS_FOOTER);
            if (!TextUtils.isEmpty(mCallerAppName) && !mIsCallingAppAdmin) {
                footer.setVisible(true);
                footer.setTitle(getFooterString());
            } else if (!mForFace && !mForBiometrics && !mForFingerprint && !mIsManagedProfile
                    && mController.isScreenLockRestrictedByAdmin()
                    && profileUserId != UserHandle.USER_NULL) {
                final StringBuilder description = new StringBuilder(
                        mDpm.getResources().getString(
                                WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK,
                                () -> getString(
                                R.string.lock_settings_picker_admin_restricted_personal_message)));
                footer.setVisible(true);
                footer.setTitle(description);

                final StringBuilder setLockText = new StringBuilder(
                        mDpm.getResources().getString(
                                WORK_PROFILE_IT_ADMIN_CANT_RESET_SCREEN_LOCK_ACTION,
                                () -> getString(
                          R.string.lock_settings_picker_admin_restricted_personal_message_action)));
                View.OnClickListener setLockClickListener = (v) -> {
                    final Bundle extras = new Bundle();
                    extras.putInt(Intent.EXTRA_USER_ID, profileUserId);
                    if (mUserPassword != null) {
                        extras.putParcelable(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
                                mUserPassword);
                    }
                    new SubSettingLauncher(getActivity())
                            .setDestination(ChooseLockGenericFragment.class.getName())
                            .setSourceMetricsCategory(getMetricsCategory())
                            .setArguments(extras)
                            .launch();
                    finish();
                };
                footer.setLearnMoreText(setLockText);
                footer.setLearnMoreAction(setLockClickListener);
            } else {
                footer.setVisible(false);
            }

            // Used for testing purposes
            findPreference(ScreenLockType.NONE.preferenceKey).setViewId(R.id.lock_none);
            findPreference(KEY_SKIP_FINGERPRINT).setViewId(R.id.lock_none);
            findPreference(KEY_SKIP_FACE).setViewId(R.id.lock_none);
            findPreference(KEY_SKIP_BIOMETRICS).setViewId(R.id.lock_none);
            findPreference(ScreenLockType.PIN.preferenceKey).setViewId(R.id.lock_pin);
            findPreference(ScreenLockType.PASSWORD.preferenceKey).setViewId(R.id.lock_password);
        }

>2.disableUnusablePreferences

处理下锁屏类型那几个是否可以显示,是否可用

        private ChooseLockGenericController mController;
        
        private void disableUnusablePreferences () {
            final PreferenceScreen entries = getPreferenceScreen();
        //循环所有支持的锁屏类型,更新其可见性以及可用性
            for (ScreenLockType lock : ScreenLockType.values()) {
                String key = lock.preferenceKey;
                Preference pref = findPreference(key);
                if (pref instanceof RestrictedPreference) {
                    //见10.1
                    boolean visible = mController.isScreenLockVisible(lock);
                    //见10.2
                    boolean enabled = mController.isScreenLockEnabled(lock);
                    if (!visible) {
                        entries.removePreference(pref);
                    } else if (!enabled) {
                        pref.setEnabled(false);
                    }
                }
            }
        }

>3.ScreenLockType

所有的锁屏类型

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"),
    PASSWORD(
            DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC,
            DevicePolicyManager.PASSWORD_QUALITY_COMPLEX,
            "unlock_set_password"),
    MANAGED(
            DevicePolicyManager.PASSWORD_QUALITY_MANAGED,
            "unlock_set_managed");

>4.updatePreferenceText

如下图,我们点击的face unlock,那么下边的forFace的值就是真的 image.png 进去的值如下,就是下边if修改的,不同的来源显示不同的文字

image.png

        private void updatePreferenceText() {
        //下边这几个if,是从对应的锁屏方式点进来的
            if (mForFingerprint) {
                setPreferenceTitle(ScreenLockType.PATTERN,
                        R.string.fingerprint_unlock_set_unlock_pattern);
                setPreferenceTitle(ScreenLockType.PIN, R.string.fingerprint_unlock_set_unlock_pin);
                setPreferenceTitle(ScreenLockType.PASSWORD,
                        R.string.fingerprint_unlock_set_unlock_password);
            } else if (mForFace) {
                setPreferenceTitle(ScreenLockType.PATTERN,
                        R.string.face_unlock_set_unlock_pattern);
                setPreferenceTitle(ScreenLockType.PIN, R.string.face_unlock_set_unlock_pin);
                setPreferenceTitle(ScreenLockType.PASSWORD,
                        R.string.face_unlock_set_unlock_password);
            } else if (mForBiometrics) {
                setPreferenceTitle(ScreenLockType.PATTERN,
                        R.string.biometrics_unlock_set_unlock_pattern);
                setPreferenceTitle(ScreenLockType.PIN, R.string.biometrics_unlock_set_unlock_pin);
                setPreferenceTitle(ScreenLockType.PASSWORD,
                        R.string.biometrics_unlock_set_unlock_password);
            }

            if (mManagedPasswordProvider.isSettingManagedPasswordSupported()) {
                setPreferenceTitle(ScreenLockType.MANAGED,
                        mManagedPasswordProvider.getPickerOptionTitle(mForFingerprint));
            } else {
                removePreference(ScreenLockType.MANAGED.preferenceKey);
            }

            if (!(mForFingerprint && mIsSetNewPassword)) {
                removePreference(KEY_SKIP_FINGERPRINT);
            }
            if (!(mForFace && mIsSetNewPassword)) {
                removePreference(KEY_SKIP_FACE);
            }
            if (!(mForBiometrics && mIsSetNewPassword)) {
                removePreference(KEY_SKIP_BIOMETRICS);
            }
        }

>5.updateCurrentPreference

查下当先设置的是哪种lock,显示summary,如下图

image.png

        private void updateCurrentPreference() {
            String currentKey = getKeyForCurrent();
            Preference preference = findPreference(currentKey);
            if (preference != null) {
                preference.setSummary(R.string.current_screen_lock);
            }
        }

        private String getKeyForCurrent() {
            final int credentialOwner = UserManager.get(getContext())
                    .getCredentialOwnerProfile(mUserId);
            if (mLockPatternUtils.isLockScreenDisabled(credentialOwner)) {
                return ScreenLockType.NONE.preferenceKey;
            }
            ScreenLockType lock =
                    ScreenLockType.fromQuality(
                            mLockPatternUtils.getKeyguardStoredPasswordQuality(credentialOwner));
            return lock != null ? lock.preferenceKey : null;
        }

8.5.onPreferenceTreeClick

看下选项的点击事件

        public boolean onPreferenceTreeClick (Preference preference) {
            writePreferenceClickMetric(preference);

            final String key = preference.getKey();
            //点击的是none或者swipe,见补充1,
            //当前是secure类型(密码,pin,pattern),见5.1
            if (!isUnlockMethodSecure(key) && mLockPatternUtils.isSecure(mUserId)) {
                // 这里需要提示删除旧的数据,见补充2
                showFactoryResetProtectionWarningDialog(key);
                return true;
            } else if (KEY_SKIP_FINGERPRINT.equals(key) || KEY_SKIP_FACE.equals(key)
                    || KEY_SKIP_BIOMETRICS.equals(key)) {
                //点击的是跳过指纹,人脸识别,生物识别,见补充4,其实加载的还是这个fragment
                Intent chooseLockGenericIntent = new Intent(getActivity(),
                    getInternalActivityClass());
                chooseLockGenericIntent.setAction(getIntent().getAction());
                // Forward the target user id to  ChooseLockGeneric.
                chooseLockGenericIntent.putExtra(Intent.EXTRA_USER_ID, mUserId);
                chooseLockGenericIntent.putExtra(CONFIRM_CREDENTIALS, !mPasswordConfirmed);
                chooseLockGenericIntent.putExtra(EXTRA_KEY_REQUESTED_MIN_COMPLEXITY,
                        mRequestedMinComplexity);
                chooseLockGenericIntent.putExtra(EXTRA_KEY_DEVICE_PASSWORD_REQUIREMENT_ONLY,
                        mOnlyEnforceDevicePasswordRequirement);
                chooseLockGenericIntent.putExtra(EXTRA_KEY_CALLER_APP_NAME, mCallerAppName);
                if (mUserPassword != null) {
                    chooseLockGenericIntent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_PASSWORD,
                            mUserPassword);
                }
                startActivityForResult(chooseLockGenericIntent, SKIP_FINGERPRINT_REQUEST);
                return true;
            } else {
            //点击的是 pattern,pin,或者password选项
                return setUnlockMethod(key);//补充3,
            }
        }

>1.isUnlockMethodSecure

如果key不是none或者swipe,返回true,否则返回false

        private boolean isUnlockMethodSecure(String unlockMethod) {
            return !(ScreenLockType.SWIPE.preferenceKey.equals(unlockMethod) ||
                    ScreenLockType.NONE.preferenceKey.equals(unlockMethod));
        }

>2.showFactoryResetProtectionWarningDialog

清除密码确认框,这里的参数是NONE或者SWIPE

        private void showFactoryResetProtectionWarningDialog(String unlockMethodToSet) {
            int title = getResIdForFactoryResetProtectionWarningTitle();
            int message = getResIdForFactoryResetProtectionWarningMessage();
            FactoryResetProtectionWarningDialog dialog =
                    FactoryResetProtectionWarningDialog.newInstance(
                            title, message, unlockMethodToSet);
            dialog.show(getChildFragmentManager(), TAG_FRP_WARNING_DIALOG);
        }

dialog的确认按钮事件如下

            .setPositiveButton(R.string.unlock_disable_frp_warning_ok,
                    (dialog, whichButton) -> {
                        String unlockMethod = args.getString(ARG_UNLOCK_METHOD_TO_SET);
                        ((ChooseLockGenericFragment) getParentFragment())
                                .setUnlockMethod(unlockMethod);//见补充3
                    })

>3.setUnlockMethod

        private boolean setUnlockMethod(String unlockMethod) {
            ScreenLockType lock = ScreenLockType.fromKey(unlockMethod);
            if (lock != null) {
                switch (lock) {
                    case NONE:
                    case SWIPE:
                    //前两种,直接修改关闭页面,见8.6
                        updateUnlockMethodAndFinish(
                                lock.defaultQuality,
                                lock == ScreenLockType.NONE,
                                false /* chooseLockSkipped */);
                        return true;
                    case PATTERN:
                    case PIN:
                    case PASSWORD:
                    case MANAGED:
                    //跳转到对应的设置页面,见8.7
                        maybeEnableEncryption(lock.defaultQuality, false);
                        return true;
                }
            }
            return false;
        }

>4.getInternalActivityClass

        protected Class<? extends ChooseLockGeneric.InternalActivity> getInternalActivityClass() {
            return ChooseLockGeneric.InternalActivity.class;
        }

8.6.updateUnlockMethodAndFinish

        void updateUnlockMethodAndFinish(int quality, boolean disabled, boolean chooseLockSkipped) {

            quality = mController.upgradeQuality(quality);
            //见补充1
            Intent intent = getIntentForUnlockMethod(quality);
            if (intent != null) {
            //非none或swipe的走这里
                if (getIntent().getBooleanExtra(EXTRA_SHOW_OPTIONS_BUTTON, false)) {
                    intent.putExtra(EXTRA_SHOW_OPTIONS_BUTTON, chooseLockSkipped);
                }
                intent.putExtra(EXTRA_CHOOSE_LOCK_GENERIC_EXTRAS, getIntent().getExtras());
                // If the caller requested Gatekeeper Password Handle to be returned, we assume it
                // came from biometric enrollment. onActivityResult will put the LockSettingsService
                // into the extras and launch biometric enrollment. This should be cleaned up,
                // since requesting a Gatekeeper Password Handle should not imply it came from
                // biometric setup/settings.
                startActivityForResult(intent,
                        mIsSetNewPassword && mRequestGatekeeperPasswordHandle
                                ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
                                : CHOOSE_LOCK_REQUEST);
                return;
            }
            //8.5.3里的none或者swipe走这里
            if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
                //有旧密码的清除旧密码数据
                //密码来源见8.3,有密码的情况进入此页会先要求输入密码,8.3回调里会记录获取的密码
                if (mUserPassword != null) {
                    mLockPatternUtils.setLockCredential(
                            LockscreenCredential.createNone(), mUserPassword, mUserId);
                }
                //none的话disable为true,swipe的话disable为false
                mLockPatternUtils.setLockScreenDisabled(disabled, mUserId);
                getActivity().setResult(Activity.RESULT_OK);
                LockScreenSafetySource.onLockScreenChange(getContext());
                finish();
            }
        }

>1.getIntentForUnlockMethod

根据给定的quality获取对应的intent或者空,比如none或者swipe类型的就是空

        private Intent getIntentForUnlockMethod(int quality) {
            Intent intent = null;
            if (quality >= DevicePolicyManager.PASSWORD_QUALITY_MANAGED) {
                intent = getLockManagedPasswordIntent(mUserPassword);
            } else if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
                intent = getLockPasswordIntent(quality);//见补充2
            } else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
                intent = getLockPatternIntent();//见补充3
            }
            return intent;
        }

>2.getLockPasswordIntent

password或者pin设置页面,ChooseLockPassword

        protected Intent getLockPasswordIntent(int quality) {
            ChooseLockPassword.IntentBuilder builder =
                    new ChooseLockPassword.IntentBuilder(getContext())
                            .setPasswordType(quality)
                            .setPasswordRequirement(
                                    mController.getAggregatedPasswordComplexity(),
                                    mController.getAggregatedPasswordMetrics())
                            .setForFingerprint(mForFingerprint)
                            .setForFace(mForFace)
                            .setForBiometrics(mForBiometrics)
                            .setUserId(mUserId)
                            .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
            if (mUserPassword != null) {
                builder.setPassword(mUserPassword);
            }
            if (mUnificationProfileId != UserHandle.USER_NULL) {
                builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential);
            }
            return builder.build();
        }

>3.getLockPatternIntent

九宫格设置页面,ChooseLockPattern

        protected Intent getLockPatternIntent() {
            ChooseLockPattern.IntentBuilder builder =
                    new ChooseLockPattern.IntentBuilder(getContext())
                            .setForFingerprint(mForFingerprint)
                            .setForFace(mForFace)
                            .setForBiometrics(mForBiometrics)
                            .setUserId(mUserId)
                            .setRequestGatekeeperPasswordHandle(mRequestGatekeeperPasswordHandle);
            if (mUserPassword != null) {
                builder.setPattern(mUserPassword);
            }
            if (mUnificationProfileId != UserHandle.USER_NULL) {
                builder.setProfileToUnify(mUnificationProfileId, mUnificationProfileCredential);
            }
            return builder.build();
        }

8.7.maybeEnableEncryption

        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()) {
                // 见8.6.1根据不同的密码类型获取不同的intent
                Intent unlockMethodIntent = getIntentForUnlockMethod(quality);
            //...设置要传递的参数
                //补充1,封装新的跳转intent
                Intent intent = getEncryptionInterstitialIntent(context, quality, required,
                        unlockMethodIntent);
            //...我们不走这里
                startActivityForResult(
                        intent,
                        mIsSetNewPassword && mRequestGatekeeperPasswordHandle
                                ? CHOOSE_LOCK_BEFORE_BIOMETRIC_REQUEST
                                : ENABLE_ENCRYPTION_REQUEST);
            } else {
                if (mForChangeCredRequiredForBoot) {
                    // Welp, couldn't change it. Oh well.
                    finish();
                    return;
                }
                //正常走这里,又回到8.6了
                updateUnlockMethodAndFinish(quality, disabled, false /* chooseLockSkipped */);
            }
        }

9.ChooseLockSettingsHelper.java

9.1.show

最终执行的就是9.2的方法,决定是否跳转到密码确认页面

        public boolean show() {
            return build().launch();
        }

>1.build

        @NonNull public ChooseLockSettingsHelper build() {
           //..
            return new ChooseLockSettingsHelper(this, mActivity, mFragment,
                    mActivityResultLauncher);
        }

>2.launch

    public boolean launch() {
        //见9.2
        return launchConfirmationActivity(mBuilder.mRequestCode, mBuilder.mTitle, mBuilder.mHeader,
                mBuilder.mDescription, mBuilder.mReturnCredentials, mBuilder.mExternal,
                mBuilder.mForceVerifyPath, mBuilder.mUserId, mBuilder.mAlternateButton,
                mBuilder.mAllowAnyUserId, mBuilder.mForegroundOnly,
                mBuilder.mRequestGatekeeperPasswordHandle);
    }

9.2.launchConfirmationActivity

  • 根据userId从数据库里读取到对应的quality值,看是否在case里,在的话说明是Pattern,pin,password里的一种,需要弹密码确认框
  • case里的区别就是跳转到9宫格图案还是密码输入页面
  • 页面跳转逻辑见9.3
  • returnCredentials 是true,参数见8.2
    private boolean launchConfirmationActivity(int request, @Nullable CharSequence title,
            @Nullable CharSequence header, @Nullable CharSequence description,
            boolean returnCredentials, boolean external, boolean forceVerifyPath,
            int userId, @Nullable CharSequence alternateButton, boolean allowAnyUser,
            boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
        final int effectiveUserId = UserManager.get(mActivity).getCredentialOwnerProfile(userId);
        //默认值是false
        boolean launched = false;
        //见5.10,获取当前的密码类型对应的quality值
        switch (mLockPatternUtils.getKeyguardStoredPasswordQuality(effectiveUserId)) {
            case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
            //9宫格是一种样式
                launched = launchConfirmationActivity(request, title, header, description,
                        returnCredentials || forceVerifyPath
                                ? ConfirmLockPattern.InternalActivity.class//跳转的类
                                : ConfirmLockPattern.class, returnCredentials, external,
                                forceVerifyPath, userId, alternateButton, allowAnyUser,
                                foregroundOnly, requestGatekeeperPasswordHandle);
                break;
            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC:
            case DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX:
            case DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC:
            case DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC:
            case DevicePolicyManager.PASSWORD_QUALITY_COMPLEX:
            case DevicePolicyManager.PASSWORD_QUALITY_MANAGED:
            //密码,pin是一种样式
                launched = launchConfirmationActivity(request, title, header, description,
                        returnCredentials || forceVerifyPath
                                ? ConfirmLockPassword.InternalActivity.class//跳转的类
                                : ConfirmLockPassword.class, returnCredentials, external,
                                forceVerifyPath, userId, alternateButton, allowAnyUser,
                                foregroundOnly, requestGatekeeperPasswordHandle);
                break;
        }
        //没有设置密码的话返回的就是默认值false,有密码的话就跳转到密码页并返回true,见9.3
        return launched;
    }

9.3.launchConfirmationActivity

    private boolean launchConfirmationActivity(int request, CharSequence title, CharSequence header,
            CharSequence message, Class<?> activityClass, boolean returnCredentials,
            boolean external, boolean forceVerifyPath, int userId,
            @Nullable CharSequence alternateButton, boolean allowAnyUser,
            boolean foregroundOnly, boolean requestGatekeeperPasswordHandle) {
        final Intent intent = new Intent();
        //设置要传递的参数..省略
        //设置要跳转的类
        intent.setClassName(SETTINGS_PACKAGE_NAME, activityClass.getName());
        intent.putExtra(SettingsBaseActivity.EXTRA_PAGE_TRANSITION_TYPE,
                SettingsTransitionHelper.TransitionType.TRANSITION_SLIDE);

        Intent inIntent = mFragment != null ? mFragment.getActivity().getIntent() :
                mActivity.getIntent();
        copyInternalExtras(inIntent, intent);
        if (external) {
            intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
            copyOptionalExtras(inIntent, intent);
            if (mActivityResultLauncher != null) {
                mActivityResultLauncher.launch(intent);
            } else if (mFragment != null) {
                mFragment.startActivity(intent);
            } else {
                mActivity.startActivity(intent);
            }
        } else {
            if (mActivityResultLauncher != null) {
                mActivityResultLauncher.launch(intent);
            } else if (mFragment != null) {
            //我们走这里
                mFragment.startActivityForResult(intent, request);
            } else {
                mActivity.startActivityForResult(intent, request);
            }
        }
        return true;
    }

9.4.密码验证页面

每次进入小节8的页面,如果已经设置了密码,那么会先跳转到输入密码页才能操作,对应的两种密码页面如下

  • 九宫格 ConfirmLockPattern.InternalActivity.class
  • 密码或者pin码 ConfirmLockPassword.InternalActivity.class

10.ChooseLockGenericController.java

10.1.isScreenLockVisible

    public boolean isScreenLockVisible(ScreenLockType type) {
        final boolean managedProfile = mContext.getSystemService(UserManager.class)
                .isManagedProfile(mUserId);
        switch (type) {
            case NONE:
                return !mHideInsecureScreenLockTypes
                    && !mContext.getResources().getBoolean(R.bool.config_hide_none_security_option)
                    && !managedProfile; // Profiles should use unified challenge instead.
            case SWIPE:
                return !mHideInsecureScreenLockTypes
                    && !mContext.getResources().getBoolean(R.bool.config_hide_swipe_security_option)
                    && !managedProfile; // Swipe doesn't make sense for profiles.
            case MANAGED:
                return mManagedPasswordProvider.isManagedPasswordChoosable();
            case PIN:
            case PATTERN:
            case PASSWORD:
                //见5.8
                return mLockPatternUtils.hasSecureLockScreen();
        }
        return true;
    }

10.2.isScreenLockEnabled

    public boolean isScreenLockEnabled(ScreenLockType type) {
    //见5.11,
        return !mLockPatternUtils.isCredentialsDisabledForUser(mUserId)
                && type.maxQuality >= upgradeQuality(PASSWORD_QUALITY_UNSPECIFIED);
    }

10.3.upgradeQuality

    public int upgradeQuality(int quality) {
        return Math.max(quality,
                Math.max(
                        LockPatternUtils.credentialTypeToPasswordQuality(
                                getAggregatedPasswordMetrics().credType),
                        PasswordMetrics.complexityLevelToMinQuality(
                                getAggregatedPasswordComplexity())
                )
        );
    }

11.总结

  • screen lock 的判定逻辑,先判断是否是secure模式,也就是(pin,password,pattern)里的一种
  • 如果是非secure模式,再根据util判断是否是disable状态(数据存储在数据库里的),none的话disable为true,其他都是false
  • lock方式选择页面,见小节8,(如果设置过密码,那么会先跳转到密码页,见9.4,输入密码以后才会)展示可用lock方式选项
  • 密码修改或者说设置页,见8.6.2以及8.6.3两种

11.1.KeyguardManager

获取系统锁的状态

KeyguardManager keyguardManager=getSystemService(KeyguardManager.class);

>1.isKeyguardSecure

设置了pin,pasword,pattern或者SIM卡锁定 为true,不设置或者是swipe为false

keyguardManager.isKeyguardSecure()

>2.isKeyguardLocked

这个当前是否是锁屏状态,只要不是None,息屏后能看到锁屏页面的都是true,

keyguardManager.isKeyguardLocked()

>3.isDeviceSecure

和补充1的区别,这里只判断pin,pasword,pattern,不包括sim卡锁定

keyguardManager.isDeviceSecure()

>4.isDeviceLocked

是否屏幕已解锁,就是需要pin,password,pattern解锁,和补充2的区别,如果是swipe的话这里也是false

keyguardManager.isDeviceLocked()