android 5.1 屏幕锁定开发相关

系统设置的activity是 Settings,另外有40多个activity继承于它,比如设置的一级菜单: wifi,蓝牙,声音,显示,安全,应用程序,语言和时间,关于设备等等。实际上都是这一个acitivy。
这里从安全设置看起,SecuritySettings.Java


以资源文件R.xml.security_settings_* 填充【根据当前锁屏方式,拥有者信息,密码显示等具体情形,加载不同的资源或配置】,具体在createPreferenceHierarchy() 和 onResume中
以改锁屏方式为主线,点击锁屏项时,onPreferenceTreeClick #587


调用,
在key值为KEY_UNLOCK_SET_OR_CHANGE则跳转到fragmen ----

`startFragment(this, "com.android.settings.ChooseLockGeneric$ChooseLockGenericFragment", `

--------------------------------

偶然间发现,设置未知来源的开关

Settings.Global.INSTALL_NON_MARKET_APPS的值 enabled ? 1 : 0)

0 :为不允许安装未知来源apk    
1 :为允许安装未知来源apk

这个值存储在了setting provider中,目录/data/data/com.android.providers.settings/的db文件,表secure的install_non_market_apps字段


android 5.1 屏幕锁定开发相关_第1张图片

试了一下adb操作发现是可以控制的

adb shell settings put secure install_non_market_apps 0 //设置不允许安装未知来源

adb shell settings get secure install_non_market_apps //获取状态

--------------------------------

回到ChooseLockGeneric.java

它有一个内部类 ChooseLockGenericFragment extends SettingsPreferenceFragment

在ChooseLockGenericFragment的updatePreferencesOrFinish()方法中有这样一行代码用于显示所有的解锁方式:

addPreferencesFromResource(R.xml.security_settings_picker);

/src/xml/security_settings_picker.xml这个文件,就是用来配置所有解锁方式的文件,来看看它的源码:




............


屏幕锁定方式一共包含无,滑动,人脸解锁,图案,PIN,密码6中方式

选择一种方式后,执行updateUnlockMethodAndFinish(方式,启用锁屏?)

继续看ChooseLockGenericFragment的 onPreferenceTreeClick()方法,这个方法就是处理每一项的点击事件的方法。

如果我们选择无,也就是没有锁屏,点亮屏幕直接进入主屏,走的就是这个if语句:

final String key = preference.getKey();
if (KEY_UNLOCK_SET_OFF.equals(key) ) {
updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true);

}
这里直接将事件交给了 updateUnlockMethodAndFinish(int quality, boolean disabled)方法处理。

这个方法的第一个参数表示解锁方式的等级,在android.app.admin.DevicePolicyManager.java中定义了各个解锁方式对应的等级值,从小到大,表示解锁方式安全性的由弱到强:

无和滑动两个对应的值都是PASSWORD_QUALITY_UNSPECIFIED = 0

注意这个方法的第二个参数disabled是一个boolean值,如果不使用任何解锁方式,也就是无,那么updateUnlockMethodAndFinish中的这个值就应该传入true;否则都应该传入false,所以源码中只有处理无选项的updateUnlockMethodAndFinish方法传入了true,其他都传入false。

我们这里分析的是无选项,所以只看它对应的代码

......
} else if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
            mChooseLockSettingsHelper.utils().clearLock(false);
            mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled);
            getActivity().setResult(Activity.RESULT_OK);
            finish();
        }
......

mChooseLockSettingsHelper.utils().clearLock(false);这行代码是用来清除所有的锁屏方式的,看一下它里面的代码:

com.android.internal.widget.LockPatternUtils.java

 /**
   * Clear any lock pattern or password.
 */
public void clearLock(boolean isFallback, int userHandle) {
    if(!isFallback) deleteGallery(userHandle);
    saveLockPassword(null, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, isFallback,
            userHandle);
    setLockPatternEnabled(false, userHandle);
    saveLockPattern(null, isFallback, userHandle);
    setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
    setLong(PASSWORD_TYPE_ALTERNATE_KEY, DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
            userHandle);
    onAfterChangingPassword(userHandle);
}

而 mChooseLockSettingsHelper.utils().setLockScreenDisabled(disabled);这个disabled值就是上面传进来的true,也就是意味着不使用任何解锁方法

接着finish之后会回调 SecuritySettings中的onActivityResult()方法。

这个方法里面会调用 createPreferenceHierarchy()方法,而这个方法中的addPreferencesFromResource(resid);就是在SecuritySettings界面显示刚刚选择的解锁方式,如图:

android 5.1 屏幕锁定开发相关_第2张图片

我们来仔细看一下代码:
在com.android.settings.SecuritySettings$$getResIdForLockUnlockScreen()

    if (!lockPatternUtils.isSecure()) {
        // if there are multiple users, disable "None" setting
        UserManager mUm = (UserManager) context. getSystemService(Context.USER_SERVICE);
        List users = mUm.getUsers(true);
        final boolean singleUser = users.size() == 1;

        if (singleUser && lockPatternUtils.isLockScreenDisabled()) {
            resid = R.xml.security_settings_lockscreen;
        } else {
            resid = R.xml.security_settings_chooser;
        }

R.xml.security_settings_lockscreen 是无对应的布局;

R.xml.security_settings_chooser 是滑动解锁对应的布局.

看一下mLockPatternUtils.isLockScreenDisabled()这个方法:

/**
 * Determine if LockScreen can be disabled. This is used, for example, to tell if we should
 * show LockScreen or go straight to the home screen.
 *
 * @return true if lock screen is can be disabled
 */
public boolean isLockScreenDisabled() {
    if (!isSecure() && getLong(DISABLE_LOCKSCREEN_KEY, 0) != 0) {
        // Check if the number of switchable users forces the lockscreen.
        final List users = UserManager.get(mContext).getUsers(true);
        final int userCount = users.size();
        int switchableUsers = 0;
        for (int i = 0; i < userCount; i++) {
            if (users.get(i).supportsSwitchTo()) {
                switchableUsers++;
            }
        }
        return switchableUsers < 2;
    }
    return false;
}

也就是说如果是isSecure()为false,并且getLong的值不为0,就显示无。

getLong的值在刚刚的setLockScreenDisabled(disabled)中已经设置为 1 了。所以就来看看isSecure()方法:

public boolean isSecure(int userId) {
    long mode = getKeyguardStoredPasswordQuality(userId);
    final boolean isPattern = mode == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
    final boolean isPassword = mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC
            || mode == DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX
            || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC
            || mode == DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC
            || mode == DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
    final boolean secure =
            isPattern && isLockPatternEnabled(userId) && savedPatternExists(userId)
            || isPassword && savedPasswordExists(userId);
    return secure;
}

由于当前的mode是
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,所以isPattern为false,所以isSecure()肯定返回false了。

最终我们看到的就是无这个选项了。

另外,滑动解锁与无的唯一区别就是,调用 updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true) 是传入的是true,也就是使用锁屏,而无传入的这个值是false。

 private LockPatternUtils mLockPatternUtils;
    mLockPatternUtils = new LockPatternUtils(getActivity());
if (KEY_SYSTEM_SAFE_NONE.equals(key)) {    //达到设置锁定方式为无
        mLockPatternUtils.clearLock(false);
        mLockPatternUtils.setLockScreenDisabled(true);
    }else if(KEY_SYSTEM_SAFE_SLIP.equals(key)){    ////达到设置锁定方式为滑动
        mLockPatternUtils.clearLock(false);
        mLockPatternUtils.setLockScreenDisabled(false);
}

  • pin码锁屏设置


之前的步骤都一样,所以我们从上面的ChooseLockGeneric.java开始分析。
继续看ChooseLockGenericFragment的 onPreferenceTreeClick()方法,
执行onPreferenceTreeClick方法之后,因为选择的是pin解锁,走的就是这个if语句:

} else if (KEY_UNLOCK_SET_PIN.equals(unlockMethod)) {
            maybeEnableEncryption(
                    DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, false);
        } ...

看一下它调用调用updateUnlockMethodAndFinish()方法,走的是哪段代码:

        final boolean isFallback = getActivity().getIntent()
            .getBooleanExtra(LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
        quality = upgradeQuality(quality, null);

        final Context context = getActivity();
        if (quality >= DevicePolicyManager.PASSWORD_QUALITY_NUMERIC) {
            int minLength = mDPM.getPasswordMinimumLength(null);
            if (minLength < MIN_PASSWORD_LENGTH) {
                minLength = MIN_PASSWORD_LENGTH;
            }
            final int maxLength = mDPM.getPasswordMaximumLength(quality);
            Intent intent = getLockPasswordIntent(context, quality, isFallback, minLength,
                    maxLength, mRequirePassword,  /* confirm credentials */false);
            if (isFallback) {
                startActivityForResult(intent, FALLBACK_REQUEST);
                return;
            } else {
                mFinishPending = true;
                intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
                startActivity(intent);
            }
        } else if ...

来看一下这段代码中的if (isFallback) {...}部分:

首先值得一提的是,如果我们选择一种安全性比较弱(介于 UNSPECIFIED 和SOMETHING之间)的解锁方式,例如语音解锁,那么我们不仅要录如自己的语音命令,还要选择一个备用的解锁方式,如图:

android 5.1 屏幕锁定开发相关_第3张图片

这里的这个isFallback就是用来判断当前这个pin解锁方式,是直接选择的呢,还是其他解锁方式的备用解锁方式。如果是直接选择的,那就直接startActivity(intent);,否则就startActivityForResult(intent, FALLBACK_REQUEST);

姑且先考虑pin码直接解锁这种情形,所以走else部分.

intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intent);
}

以这种方式启动Activity的意思就是说,因为ChooseLockGeneric是由SecuritySettings启动的,所以ChooseLockGeneric启动ChooseLockPattern之后, ChooseLockPattern的setResult方法会将结果返回给SecuritySettings而不是ChooseLockGeneric.java,这是应该注意的。

接着就是绘制两次图案了,在ChooseLockPassword.java中的handNext()方法中有这样一行代码:

    if (mFirstPin.equals(pin)) {
                final boolean isFallback = getActivity().getIntent().getBooleanExtra(
                        LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK, false);
                boolean wasSecureBefore = mLockPatternUtils.isSecure();
                mLockPatternUtils.clearLock(isFallback);
                final boolean required = getActivity().getIntent().getBooleanExtra(
                        EncryptionInterstitial.EXTRA_REQUIRE_PASSWORD, true);
                mLockPatternUtils.setCredentialRequiredToDecrypt(required);
                mLockPatternUtils.saveLockPassword(pin, mRequestedQuality, isFallback);
                getActivity().setResult(RESULT_FINISHED);
                getActivity().finish();
                mDone = true;
                if (!wasSecureBefore) {
                    startActivity(getRedactionInterstitialIntent(getActivity()));
                }
            } 

关键两句

mLockPatternUtils.setCredentialRequiredToDecrypt(required);
mLockPatternUtils.saveLockPassword(pin, mRequestedQuality, isFallback);

来看一下LockPatternUtils.java里的setCredentialRequiredToDecrypt()

 public void setCredentialRequiredToDecrypt(boolean required) {
    if (getCurrentUser() != UserHandle.USER_OWNER) {
        Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
        return;
    }
    Settings.Global.putInt(mContext.getContentResolver(),
            Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT, required ? 1 : 0);
}

验证pin密码

/**
* Check to see if a password matches the saved password.  If no password exists,
 * always returns true.
 * @param password The password to check.
 * @return Whether the password matches the stored one.
 */
public boolean checkPassword(String password) {
final int userId = getCurrentOrCallingUserId();
    try {
        return getLockSettings().checkPassword(password, userId);
    } catch (RemoteException re) {
return true;
    }
}
  • 图案解锁方式

接着来看一下选择图案解锁方式的流程

. 之前的步骤都一样,所以我们还是从上面的ChooseLockGeneric.java开始分析。

执行onPreferenceTreeClick方法之后,因为选择的是图案解锁,走的就是这个if语句

else if (KEY_UNLOCK_SET_PATTERN.equals(key)) {
 updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, false);
}

DevicePolicyManager.PASSWORD_QUALITY_SOMETHING的值是0x10000

. 看一下它调用调用updateUnlockMethodAndFinish()方法,走的是哪段代码:

else if (quality == DevicePolicyManager.PASSWORD_QUALITY_SOMETHING) {
  Intent intent = new Intent(getActivity(), ChooseLockPattern.class);
  intent.putExtra("key_lock_method", "pattern");
  intent.putExtra(CONFIRM_CREDENTIALS, false);
  intent.putExtra(IphoneLockPatternUtils.LOCKSCREEN_WEAK_FALLBACK,
          isFallback);   //M: modify for voice unlock
  if (isFallback) {
      //M: add for voice unlock @{
      String isFallbackFor = getActivity().getIntent().
          getStringExtra(IphoneLockPatternUtils.LOCKSCREEN_WEAK_FALLBACK_FOR);
      String commandKey = getActivity().getIntent().
          getStringExtra(IphoneLockPatternUtils.SETTINGS_COMMAND_KEY);
      String commandValue = getActivity().getIntent().
          getStringExtra(IphoneLockPatternUtils.SETTINGS_COMMAND_VALUE);
      intent.putExtra(IphoneLockPatternUtils.SETTINGS_COMMAND_KEY, commandKey);
      intent.putExtra(IphoneLockPatternUtils.SETTINGS_COMMAND_VALUE, commandValue);
      intent.putExtra(IphoneLockPatternUtils.LOCKSCREEN_WEAK_FALLBACK_FOR, isFallbackFor);
      //@}
      startActivityForResult(intent, FALLBACK_REQUEST);
      return;
  } else {
      mFinishPending = true;
      intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
      startActivity(intent);
  }
}

来看一下这段代码中的if (isFallback) {...}部分:

之前说到是,如果我们选择一种安全性比较弱(介于 UNSPECIFIED 和SOMETHING之间)的解锁方式,
这里的这个isFallback就是用来判断当前这个图案解锁方式,是直接选择的呢,还是其他解锁方式的备用解锁方式。如果是直接选择的,那就直接startActivity(intent);,否则就

startActivityForResult(intent, FALLBACK_REQUEST);

我们暂且先考虑直接选择图案解锁这种情形,也就是走else部分。

intent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
startActivity(intent);
}

以这种方式启动Activity的意思就是说,因为ChooseLockGeneric是由SecuritySettings启动的,所以ChooseLockGeneric启动ChooseLockPattern之后, ChooseLockPattern的setResult方法会将结果返回给SecuritySettings而不是ChooseLockGeneric.java,这是应该注意的。

  1. 接着就是绘制两次图案了,在ChooseLockPattern中的saveChosenPatternAndFinish()方法中有这样一行代码:

utils.saveIphoneLockPattern(mChosenPattern, isFallback, isFallbackFor);
看一下这个方法的内部:

android 5.1 屏幕锁定开发相关_第4张图片

setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);其实就是用来标识图案解锁这种方式的,在下面的显示解锁方式时会用到。

  1. 最后还是来看一下SecuritySettings.java中的createPreferenceHierarchy()方法:
android 5.1 屏幕锁定开发相关_第5张图片

首先要判断mLockPatternUtils.getKeyguardStoredPasswordQuality()的值,来看一下这个方法的具体实现:

android 5.1 屏幕锁定开发相关_第6张图片

一目了然,这个getLong获取的值就是上面我们提到的标识图案解锁的值,所以必然走的是这个case:

case DevicePolicyManager.PASSWORD_QUALITY_SOMETHING:
resid = R.xml.security_settings_pattern;
break;

最终显示出来的就是我们选择了图案解锁。

  • --THE END.
  • 感谢wisim.me提供的源码解析启发

你可能感兴趣的:(android 5.1 屏幕锁定开发相关)