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

系統(tǒng)設置的activity是 Settings,另外有40多個activity繼承于它蚊伞,比如設置的一級菜單: wifi席赂,藍牙,聲音时迫,顯示氧枣,安全,應用程序别垮,語言和時間,關于設備等等扎谎。實際上都是這一個acitivy碳想。
這里從安全設置看起,SecuritySettings.Java


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


調用拐叉,
在key值為KEY_UNLOCK_SET_OR_CHANGE則跳轉到fragmen ----

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

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

偶然間發(fā)現(xià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 //設置不允許安裝未知來源

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

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

回到ChooseLockGeneric.java

它有一個內部類 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()方法乎婿,這個方法就是處理每一項的點擊事件的方法测僵。

如果我們選擇無,也就是沒有鎖屏次酌,點亮屏幕直接進入主屏恨课,走的就是這個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中定義了各個解鎖方式對應的等級值剂公,從小到大希俩,表示解鎖方式安全性的由弱到強:

無和滑動兩個對應的值都是PASSWORD_QUALITY_UNSPECIFIED = 0

注意這個方法的第二個參數(shù)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值就是上面?zhèn)鬟M來的true,也就是意味著不使用任何解鎖方法

接著finish之后會回調 SecuritySettings中的onActivityResult()方法怠硼。

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

我們來仔細看一下代碼:
在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 是無對應的布局;

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<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)設置為 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了眯牧。

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

另外,滑動解鎖與無的唯一區(qū)別就是,調用 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開始分析禁偎。
繼續(xù)看ChooseLockGenericFragment的 onPreferenceTreeClick()方法,
執(zhí)行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之間)的解鎖方式盒至,例如語音解鎖,那么我們不僅要錄如自己的語音命令,還要選擇一個備用的解鎖方式枷遂,如圖:

這里的這個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開始分析桦山。

執(zhí)行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);
看一下這個方法的內部:

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

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

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

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

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

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

  • --THE END.
  • 感謝wisim.me提供的源碼解析啟發(fā)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子席爽,更是在濱河造成了極大的恐慌意荤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件只锻,死亡現(xiàn)場離奇詭異玖像,居然都是意外死亡,警方通過查閱死者的電腦和手機炬藤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進店門御铃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人沈矿,你說我怎么就攤上這事上真。” “怎么了羹膳?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵睡互,是天一觀的道長。 經(jīng)常有香客問我陵像,道長就珠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任醒颖,我火速辦了婚禮妻怎,結果婚禮上,老公的妹妹穿的比我還像新娘泞歉。我一直安慰自己逼侦,他們只是感情好,可當我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布腰耙。 她就那樣靜靜地躺著榛丢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挺庞。 梳的紋絲不亂的頭發(fā)上晰赞,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機與錄音选侨,去河邊找鬼掖鱼。 笑死,一個胖子當著我的面吹牛援制,可吹牛的內容都是我干的锨用。 我是一名探鬼主播,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼隘谣,長吁一口氣:“原來是場噩夢啊……” “哼增拥!你這毒婦竟也來了啄巧?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤掌栅,失蹤者是張志新(化名)和其女友劉穎秩仆,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猾封,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡澄耍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晌缘。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片齐莲。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖磷箕,靈堂內的尸體忽然破棺而出选酗,到底是詐尸還是另有隱情,我是刑警寧澤岳枷,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布芒填,位于F島的核電站,受9級特大地震影響空繁,放射性物質發(fā)生泄漏殿衰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一盛泡、第九天 我趴在偏房一處隱蔽的房頂上張望闷祥。 院中可真熱鬧,春花似錦傲诵、人聲如沸凯砍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至颅痊,卻和暖如春殖熟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斑响。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工菱属, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人舰罚。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓纽门,卻偏偏與公主長得像,于是被迫代替她去往敵國和親营罢。 傳聞我的和親對象是個殘疾皇子赏陵,可洞房花燭夜當晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內容