android 5.1 屏幕鎖定開發(fā)相關(guān)

系統(tǒng)設(shè)置的activity是 Settings,另外有40多個activity繼承于它,比如設(shè)置的一級菜單: wifi,藍(lán)牙,聲音,顯示,安全,應(yīng)用程序,語言和時間,關(guān)于設(shè)備等等。實際上都是這一個acitivy。
這里從安全設(shè)置看起,SecuritySettings.Java


以資源文件R.xml.security_settings_* 填充【根據(jù)當(dāng)前鎖屏方式,擁有者信息,密碼顯示等具體情形,加載不同的資源或配置】,具體在createPreferenceHierarchy() 和 onResume中
以改鎖屏方式為主線,點擊鎖屏項時,onPreferenceTreeClick #587


調(diào)用,
在key值為KEY_UNLOCK_SET_OR_CHANGE則跳轉(zhuǎn)到fragmen ----

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

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

偶然間發(fā)現(xiàn),設(shè)置未知來源的開關(guān)

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字段



試了一下adb操作發(fā)現(xiàn)是可以控制的

adb shell settings put secure install_non_market_apps 0 //設(shè)置不允許安裝未知來源

adb shell settings get secure install_non_market_apps //獲取狀態(tài)

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

回到ChooseLockGeneric.java

它有一個內(nèi)部類 ChooseLockGenericFragment extends SettingsPreferenceFragment

在ChooseLockGenericFragment的updatePreferencesOrFinish()方法中有這樣一行代碼用于顯示所有的解鎖方式:

addPreferencesFromResource(R.xml.security_settings_picker);

/src/xml/security_settings_picker.xml這個文件,就是用來配置所有解鎖方式的文件,來看看它的源碼:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
        android:key="unlock_set_off"
        android:title="@string/unlock_set_unlock_off_title"
        android:persistent="false"/>
<PreferenceScreen
        android:key="unlock_set_none"
        android:title="@string/unlock_set_unlock_none_title"
        android:persistent="false"/>
............
<PreferenceScreen
        android:key="unlock_set_fingerprint"
        android:title="@string/unlock_set_unlock_fingerprint_title"
        android:persistent="false"/>
</PreferenceScreen>

屏幕鎖定方式一共包含無,滑動,人臉解鎖,圖案,PIN,密碼6中方式

選擇一種方式后,執(zhí)行updateUnlockMethodAndFinish(方式,啟用鎖屏?)

繼續(xù)看ChooseLockGenericFragment的 onPreferenceTreeClick()方法,這個方法就是處理每一項的點擊事件的方法。

如果我們選擇無,也就是沒有鎖屏,點亮屏幕直接進(jìn)入主屏,走的就是這個if語句:

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

}
這里直接將事件交給了 updateUnlockMethodAndFinish(int quality, boolean disabled)方法處理。

這個方法的第一個參數(shù)表示解鎖方式的等級,在android.app.admin.DevicePolicyManager.java中定義了各個解鎖方式對應(yīng)的等級值,從小到大,表示解鎖方式安全性的由弱到強(qiáng):

無和滑動兩個對應(yīng)的值都是PASSWORD_QUALITY_UNSPECIFIED = 0

注意這個方法的第二個參數(shù)disabled是一個boolean值,如果不使用任何解鎖方式,也就是無,那么updateUnlockMethodAndFinish中的這個值就應(yīng)該傳入true;否則都應(yīng)該傳入false,所以源碼中只有處理無選項的updateUnlockMethodAndFinish方法傳入了true,其他都傳入false。

我們這里分析的是無選項,所以只看它對應(yīng)的代碼

......
} 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值就是上面?zhèn)鬟M(jìn)來的true,也就是意味著不使用任何解鎖方法

接著finish之后會回調(diào) SecuritySettings中的onActivityResult()方法。

這個方法里面會調(diào)用 createPreferenceHierarchy()方法,而這個方法中的addPreferencesFromResource(resid);就是在SecuritySettings界面顯示剛剛選擇的解鎖方式,如圖:

我們來仔細(xì)看一下代碼:
在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<UserInfo> 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 是無對應(yīng)的布局;

R.xml.security_settings_chooser 是滑動解鎖對應(yīng)的布局.

看一下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<UserInfo> 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)中已經(jīng)設(shè)置為 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;
}

由于當(dāng)前的mode是
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,所以isPattern為false,所以isSecure()肯定返回false了。

最終我們看到的就是無這個選項了。

另外,滑動解鎖與無的唯一區(qū)別就是,調(diào)用 updateUnlockMethodAndFinish(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, true) 是傳入的是true,也就是使用鎖屏,而無傳入的這個值是false。

 private LockPatternUtils mLockPatternUtils;
    mLockPatternUtils = new LockPatternUtils(getActivity());
if (KEY_SYSTEM_SAFE_NONE.equals(key)) {    //達(dá)到設(shè)置鎖定方式為無
        mLockPatternUtils.clearLock(false);
        mLockPatternUtils.setLockScreenDisabled(true);
    }else if(KEY_SYSTEM_SAFE_SLIP.equals(key)){    ////達(dá)到設(shè)置鎖定方式為滑動
        mLockPatternUtils.clearLock(false);
        mLockPatternUtils.setLockScreenDisabled(false);
}

  • pin碼鎖屏設(shè)置


之前的步驟都一樣,所以我們從上面的ChooseLockGeneric.java開始分析。
繼續(xù)看ChooseLockGenericFragment的 onPreferenceTreeClick()方法,
執(zhí)行onPreferenceTreeClick方法之后,因為選擇的是pin解鎖,走的就是這個if語句:

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

看一下它調(diào)用調(diào)用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之間)的解鎖方式,例如語音解鎖,那么我們不僅要錄如自己的語音命令,還要選擇一個備用的解鎖方式,如圖:

這里的這個isFallback就是用來判斷當(dāng)前這個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方法會將結(jié)果返回給SecuritySettings而不是ChooseLockGeneric.java,這是應(yīng)該注意的。

接著就是繪制兩次圖案了,在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()));
                }
            } 

關(guān)鍵兩句

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開始分析。

執(zhí)行onPreferenceTreeClick方法之后,因為選擇的是圖案解鎖,走的就是這個if語句

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

DevicePolicyManager.PASSWORD_QUALITY_SOMETHING的值是0x10000

. 看一下它調(diào)用調(diào)用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就是用來判斷當(dāng)前這個圖案解鎖方式,是直接選擇的呢,還是其他解鎖方式的備用解鎖方式。如果是直接選擇的,那就直接startActivity(intent);,否則就

startActivityForResult(intent, FALLBACK_REQUEST);

我們暫且先考慮直接選擇圖案解鎖這種情形,也就是走else部分。

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

以這種方式啟動Activity的意思就是說,因為ChooseLockGeneric是由SecuritySettings啟動的,所以ChooseLockGeneric啟動ChooseLockPattern之后, ChooseLockPattern的setResult方法會將結(jié)果返回給SecuritySettings而不是ChooseLockGeneric.java,這是應(yīng)該注意的。

  1. 接著就是繪制兩次圖案了,在ChooseLockPattern中的saveChosenPatternAndFinish()方法中有這樣一行代碼:

utils.saveIphoneLockPattern(mChosenPattern, isFallback, isFallbackFor);
看一下這個方法的內(nèi)部:

setLong(PASSWORD_TYPE_KEY, DevicePolicyManager.PASSWORD_QUALITY_SOMETHING);其實就是用來標(biāo)識圖案解鎖這種方式的,在下面的顯示解鎖方式時會用到。

  1. 最后還是來看一下SecuritySettings.java中的createPreferenceHierarchy()方法:

首先要判斷mLockPatternUtils.getKeyguardStoredPasswordQuality()的值,來看一下這個方法的具體實現(xiàn):

一目了然,這個getLong獲取的值就是上面我們提到的標(biāo)識圖案解鎖的值,所以必然走的是這個case:

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

最終顯示出來的就是我們選擇了圖案解鎖。

  • --THE END.
  • 感謝wisim.me提供的源碼解析啟發(fā)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容