最近大體看了一下android源碼鎖屏模塊,順便把自己的收獲在此記錄下來(lái),希望對(duì)研究鎖屏的同行們有所幫助(對(duì)于鎖屏模塊,本人也沒(méi)什么時(shí)間去真正的深究,只是摸清了個(gè)大概,若有奇異和錯(cuò)誤之處,懇請(qǐng)指出)
好了,廢話不多說(shuō)了。
Android源碼模塊鎖屏大體分為兩種:
1.LockScreen: 系統(tǒng)默認(rèn)的鎖屏,就是我們所常見(jiàn)的系統(tǒng)原生波紋解鎖(涉及MultiWaveView視圖類)。如下圖:
2.UnlockScreen: 進(jìn)入手機(jī)的設(shè)置----->安全----->屏幕鎖定。在列表中將看到的可選擇項(xiàng):圖案,PIN,密碼等鎖屏都?xì)w為UnlockScreen。(可選擇任意一項(xiàng)切換鎖屏)
鎖屏相關(guān)源碼所在路徑:
1.鎖屏模塊的框架源碼所在路徑為:frameworks\base\policy\src\com\android\internal\policy\impl(本文所涉及的代碼都在這個(gè)目錄里)
2.相關(guān)的鎖屏自定義View類及與其關(guān)聯(lián)類的源碼所在路徑為:frameworks\base\core\java\com\android\internal\widget
開(kāi)機(jī)繪制鎖屏流程代碼分析:
手機(jī)開(kāi)機(jī)時(shí),在SystemServer類的init2()方法中會(huì)啟動(dòng)線程類ServerThread的run方法如下:
- class ServerThread extends Thread
- {
-
- @Override
- public void run()
- {
- WindowManagerService wm = null;
- ...
- try
- {
- wm.systemReady();
- } catch (Throwable e)
- {
- reportWtf("making Window Manager Service ready", e);
- }
- ...
- }
- }
-
- <span style="font-size:14px;"> </span>
------>上述代碼中的wm為WindowManagerService的引用,所以,wm.systemReady()為調(diào)用WindowManagerService的systemReady()方法,如下代碼:
- public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs
- {
- final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();
- ...
- public void systemReady() {
- mPolicy.systemReady();
- }
- ...
- }
------>WindowManagerPolicy的實(shí)現(xiàn)類為PhoneWindowManager,所以,接著調(diào)用到PhoneWindowManager的systemReady,如下:
- public class PhoneWindowManager implements WindowManagerPolicy
- {
- KeyguardViewMediator mKeyguardMediator;
- ...
-
- public void systemReady() {
-
- mKeyguardMediator.onSystemReady();
- android.os.SystemProperties.set("dev.bootcomplete", "1");
- synchronized (mLock) {
- updateOrientationListenerLp();
- mSystemReady = true;
- mHandler.post(new Runnable() {
- public void run() {
- updateSettings();
- }
- });
- }
- }
- ...
- }
------>接著,調(diào)用到KeyguardViewMediator類的onSystemReady()方法如下:
- public class KeyguardViewMediator implements KeyguardViewCallback,
- KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback
- {
- ...
-
-
-
-
- public void onSystemReady() {
- synchronized (this) {
- if (DEBUG) Log.d(TAG, "onSystemReady");
- mSystemReady = true;
- doKeyguardLocked();
- }
- }
- ...
- }
------>調(diào)用KeyguardViewMediator.doKeyguardLocked方法,在該方法中,先執(zhí)行一些條件判斷,若滿足直接返回。若不直接返回,則緊接著調(diào)用KeyguardViewMediator. showLocked方法,代碼如下:
- ...
-
-
-
-
- private void showLocked() {
- if (DEBUG) Log.d(TAG, "showLocked");
-
- mShowKeyguardWakeLock.acquire();
- Message msg = mHandler.obtainMessage(SHOW);
- mHandler.sendMessage(msg);
- }
- ...
----->通過(guò)handler發(fā)送消息SHOW到handleMessage處理,如下:
- ...
- *
- * This handler will be associated with the policy thread, which will also
- * be the UI thread of the keyguard. Since the apis of the policy, and therefore
- * this class, can be called by other threads, any action that directly
- * interacts with the keyguard ui should be posted to this handler, rather
- * than called directly.
- */
-
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case TIMEOUT:
- handleTimeout(msg.arg1);
- return ;
- case SHOW:
- handleShow();
- return ;
- case HIDE:
- handleHide();
- return ;
- case RESET:
- handleReset();
- return ;
- case VERIFY_UNLOCK:
- handleVerifyUnlock();
- return;
- case NOTIFY_SCREEN_OFF:
- handleNotifyScreenOff();
- return;
- case NOTIFY_SCREEN_ON:
- handleNotifyScreenOn((KeyguardViewManager.ShowListener)msg.obj);
- return;
- case WAKE_WHEN_READY:
- handleWakeWhenReady(msg.arg1);
- return;
- case KEYGUARD_DONE:
- handleKeyguardDone(msg.arg1 != 0);
- return;
- case KEYGUARD_DONE_DRAWING:
- handleKeyguardDoneDrawing();
- return;
- case KEYGUARD_DONE_AUTHENTICATING:
- keyguardDone(true);
- return;
- case SET_HIDDEN:
- handleSetHidden(msg.arg1 != 0);
- break;
- case KEYGUARD_TIMEOUT:
- synchronized (KeyguardViewMediator.this) {
- doKeyguardLocked();
- }
- break;
- }
- }
- };
- ...
------>當(dāng)case SHOW:時(shí),調(diào)用 handleShow方法,如下:
- private KeyguardViewManager mKeyguardViewManager;
- ...
-
-
-
-
-
- private void handleShow() {
- synchronized (KeyguardViewMediator.this) {
- if (DEBUG) Log.d(TAG, "handleShow");
- if (!mSystemReady) return;
-
- mKeyguardViewManager.show();
- mShowing = true;
- adjustUserActivityLocked();
- adjustStatusBarLocked();
- try {
- ActivityManagerNative.getDefault().closeSystemDialogs("lock");
- } catch (RemoteException e) {
- }
-
-
- playSounds(true);
-
- mShowKeyguardWakeLock.release();
- }
- }
- ...
----->接著調(diào)用KeyguardViewManager的show方法。KeyguardViewManager.show()中,會(huì)對(duì)KeyguardViewHost(mKeyguardHost)和LockPatternKeyguardView(mKeyguardView)是否為空進(jìn)行判斷:
1).若KeyguardViewHost為空,則創(chuàng)建KeyguardViewHost,同時(shí)設(shè)置更新其相關(guān)的布局參數(shù)。然后將KeyguardViewHost對(duì)象添加到WindowManagerImpl中。
2). 若LockPatternKeyguardView為空,創(chuàng)建LockPatternKeyguardView對(duì)象,通過(guò)調(diào)用LockPatternKeyguardViewProperties.createKeyguardView()創(chuàng)建。同時(shí)為它設(shè)置回調(diào)。然后將創(chuàng)建得到的對(duì)象添加到KeyguardViewHost。
代碼如下:
- public class KeyguardViewManager implements KeyguardWindowController {
- ...
- private FrameLayout mKeyguardHost;
- private KeyguardViewBase mKeyguardView;
-
- private final KeyguardViewProperties mKeyguardViewProperties;
- ...
-
-
-
-
-
- public synchronized void show() {
- if (DEBUG) Log.d(TAG, "show(); mKeyguardView==" + mKeyguardView);
-
- Resources res = mContext.getResources();
- boolean enableScreenRotation =
- SystemProperties.getBoolean("lockscreen.rot_override",false)
- || res.getBoolean(R.bool.config_enableLockScreenRotation);
- if (mKeyguardHost == null) {
- if (DEBUG) Log.d(TAG, "keyguard host is null, creating it...");
-
- mKeyguardHost = new KeyguardViewHost(mContext, mCallback);
-
- final int stretch = ViewGroup.LayoutParams.MATCH_PARENT;
- int flags = WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN
- | WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER
- | WindowManager.LayoutParams.FLAG_KEEP_SURFACE_WHILE_ANIMATING
-
- ;
- if (!mNeedsInput) {
- flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
- }
- if (ActivityManager.isHighEndGfx(((WindowManager)mContext.getSystemService(
- Context.WINDOW_SERVICE)).getDefaultDisplay())) {
- flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- }
- WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- stretch, stretch, WindowManager.LayoutParams.TYPE_KEYGUARD,
- flags, PixelFormat.TRANSLUCENT);
- lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
- lp.windowAnimations = com.android.internal.R.style.Animation_LockScreen;
- if (ActivityManager.isHighEndGfx(((WindowManager)mContext.getSystemService(
- Context.WINDOW_SERVICE)).getDefaultDisplay())) {
- lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
- lp.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED;
- }
- lp.setTitle("Keyguard");
- mWindowLayoutParams = lp;
-
- mViewManager.addView(mKeyguardHost, lp);
- }
-
- if (enableScreenRotation) {
- if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen On!");
- mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR;
- } else {
- if (DEBUG) Log.d(TAG, "Rotation sensor for lock screen Off!");
- mWindowLayoutParams.screenOrientation = ActivityInfo.SCREEN_ORIENTATION_NOSENSOR;
- }
-
- mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
-
- if (mKeyguardView == null) {
- if (DEBUG) Log.d(TAG, "keyguard view is null, creating it...");
-
-
- */
- mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this);
- mKeyguardView.setId(R.id.lock_screen);
-
- mKeyguardView.setCallback(mCallback);
-
- final ViewGroup.LayoutParams lp = new FrameLayout.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT);
-
-
- mKeyguardHost.addView(mKeyguardView, lp);
-
- if (mScreenOn) {
-
- mKeyguardView.show();
- }
- }
-
-
-
-
-
- int visFlags =
- ( View.STATUS_BAR_DISABLE_BACK
- | View.STATUS_BAR_DISABLE_HOME
- );
- mKeyguardHost.setSystemUiVisibility(visFlags);
-
- mViewManager.updateViewLayout(mKeyguardHost, mWindowLayoutParams);
- mKeyguardHost.setVisibility(View.VISIBLE);
- mKeyguardView.requestFocus();
- }
- ...
- }
------>在上面的代碼中,當(dāng)KeyguardViewHost為空時(shí),首先會(huì)調(diào)用KeyguardViewProperties的實(shí)現(xiàn)類LockPatternKeyguardViewProperties的createKeyguardView方法,來(lái)構(gòu)造一個(gè)LockPatternKeyguardView對(duì)象,如下:
- <span style="font-size:14px;">public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {
- ...
-
- public KeyguardViewBase createKeyguardView(Context context,
- KeyguardUpdateMonitor updateMonitor,
- KeyguardWindowController controller) {
- return new LockPatternKeyguardView(context, updateMonitor,
- mLockPatternUtils, controller);
- }
- ...
- }</span>
------->而在LockPatternKeyguardView的構(gòu)造函數(shù)中,有如下調(diào)用(以下的流程代碼實(shí)現(xiàn)均在LockPatternKeyguardView中處理):
-
-
-
-
-
-
-
- public LockPatternKeyguardView(
- Context context,
- KeyguardUpdateMonitor updateMonitor,
- LockPatternUtils lockPatternUtils,
- KeyguardWindowController controller) {
- ...
- updateScreen(getInitialMode(), false);
- ...
-
- }
----->getInitialMode()得到當(dāng)前鎖屏模式(lock or unlock),代碼如下:
- ...
- *
- * Given the current state of things, what should be the initial mode of
- * the lock screen (lock or unlock).
- */
-
- private Mode getInitialMode() {
- final IccCard.State simState = mUpdateMonitor.getSimState();
- if (stuckOnLockScreenBecauseSimMissing() ||
- (simState == IccCard.State.PUK_REQUIRED &&
- !mLockPatternUtils.isPukUnlockScreenEnable())) {
- return Mode.LockScreen;
- } else {
- if (!isSecure() || mShowLockBeforeUnlock) {
- return Mode.LockScreen;
- } else {
- return Mode.UnlockScreen;
- }
- }
- }
- ...
----->再回到updateScreen(getInitialMode(), false),該函數(shù)的實(shí)現(xiàn)如下:
- ...
- /根據(jù)參數(shù)(Lock/unLock),判斷顯示為L(zhǎng)ockScreen或者UnlockScreen界面
- private void updateScreen(Mode mode, boolean force) {
-
- if (DEBUG_CONFIGURATION) Log.v(TAG, "**** UPDATE SCREEN: mode=" + mode
- + " last mode=" + mMode + ", force = " + force, new RuntimeException());
-
- mMode = mode;
-
-
- if (mode == Mode.LockScreen || mShowLockBeforeUnlock) {
- if (force || mLockScreen == null) {
-
- recreateLockScreen();
- }
- }
-
-
-
- if (mode == Mode.UnlockScreen) {
-
- final UnlockMode unlockMode = getUnlockMode();
- if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
-
- recreateUnlockScreen(unlockMode);
- }
- }
-
-
- final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen;
- final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen;
-
-
-
- mWindowController.setNeedsInput(((KeyguardScreen)visibleScreen).needsInput());
-
- if (DEBUG_CONFIGURATION) {
- Log.v(TAG, "Gone=" + goneScreen);
- Log.v(TAG, "Visible=" + visibleScreen);
- }
-
- if (mScreenOn) {
- if (goneScreen != null && goneScreen.getVisibility() == View.VISIBLE) {
- ((KeyguardScreen) goneScreen).onPause();
- }
- if (visibleScreen.getVisibility() != View.VISIBLE) {
- ((KeyguardScreen) visibleScreen).onResume();
- }
- }
-
- if (goneScreen != null) {
- goneScreen.setVisibility(View.GONE);
- }
- visibleScreen.setVisibility(View.VISIBLE);
- requestLayout();
-
- if (!visibleScreen.requestFocus()) {
- throw new IllegalStateException("keyguard screen must be able to take "
- + "focus when shown " + visibleScreen.getClass().getCanonicalName());
- }
- }
- ...
------>在updateScreen(getInitialMode(), false)中,對(duì)傳進(jìn)來(lái)的參數(shù)Mode進(jìn)行對(duì)等判斷:
1). 若為L(zhǎng)ockScreen模式鎖屏,則如下:
- <span style="font-family:Comic Sans MS;font-size:18px;">
- if (mode == Mode.LockScreen || mShowLockBeforeUnlock) {
- if (force || mLockScreen == null) {
-
- recreateLockScreen();
- }
- }</span>
----->然后調(diào)用到LockPatternKeyguardView.recreateLockScreen(),在該函數(shù)中,首先會(huì)對(duì)LockScreen進(jìn)行判斷,若之前已存在該對(duì)象,則進(jìn)行移除。然后接著再重新調(diào)用createLockScreen()構(gòu)建LockScreen對(duì)象。然后將該對(duì)象添加到LockPatternKeyguardView中。createLockScreen()的代碼如下:
- ...
- 創(chuàng)建lockScreen
- View createLockScreen() {
- View lockView = new LockScreen(
- mContext,
- mConfiguration,
- mLockPatternUtils,
- mUpdateMonitor,
- mKeyguardScreenCallback);
- initializeTransportControlView(lockView);
- return lockView;
- }
- ...
2).若為UnlockScreen模式鎖屏,則如下:
-
-
- if (mode == Mode.UnlockScreen) {
-
- final UnlockMode unlockMode = getUnlockMode();
- if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) {
-
- recreateUnlockScreen(unlockMode);
- }
- }
----->然后調(diào)用到LockPatternKeyguardView.recreateUnlockScreen(unlockMode),在該函數(shù)中,進(jìn)行的處理和recreateLockScreen函數(shù)中的處理原則基本上一致。則調(diào)用createUnlockScreen(unlockMode)時(shí),會(huì)根據(jù)unlockMode的不同創(chuàng)建相應(yīng)的UnlockScreen具體解鎖項(xiàng)。
recreateUnlockScreen如下代碼:
- ...
- 重新構(gòu)建UnlockScreen
- private void recreateUnlockScreen(UnlockMode unlockMode) {
- if (mUnlockScreen != null) {
- ((KeyguardScreen) mUnlockScreen).onPause();
- ((KeyguardScreen) mUnlockScreen).cleanUp();
-
- removeView(mUnlockScreen);
- }
-
- mUnlockScreen = createUnlockScreenFor(unlockMode);
- mUnlockScreen.setVisibility(View.INVISIBLE);
-
- addView(mUnlockScreen);
- }
- ...
----->接著調(diào)用createUnlockScreenFor方法,在該方法中會(huì)根據(jù)傳進(jìn)來(lái)的參數(shù)UnlockMode(定義UnlockScreen可選項(xiàng)的枚舉類)判斷,來(lái)決定創(chuàng)建啟用對(duì)應(yīng)的UnlockScreen,代碼實(shí)現(xiàn)如下:
- ...
- 根據(jù)不同的Unlock Mode , 創(chuàng)建不同的UnlockScreen
- View createUnlockScreenFor(UnlockMode unlockMode) {
- View unlockView = null;
-
- if (DEBUG) Log.d(TAG,
- "createUnlockScreenFor(" + unlockMode + "): mEnableFallback=" + mEnableFallback);
-
- if (unlockMode == UnlockMode.Pattern) {
-
- PatternUnlockScreen view = new PatternUnlockScreen(
- mContext,
- mConfiguration,
- mLockPatternUtils,
- mUpdateMonitor,
- mKeyguardScreenCallback,
- mUpdateMonitor.getFailedAttempts());
- view.setEnableFallback(mEnableFallback);
- unlockView = view;
- } else if (unlockMode == UnlockMode.SimPuk) {
- unlockView = new SimPukUnlockScreen(
- mContext,
- mConfiguration,
- mUpdateMonitor,
- mKeyguardScreenCallback,
- mLockPatternUtils);
- } else if (unlockMode == UnlockMode.SimPin) {
-
- unlockView = new SimUnlockScreen(
- mContext,
- mConfiguration,
- mUpdateMonitor,
- mKeyguardScreenCallback,
- mLockPatternUtils);
- } else if (unlockMode == UnlockMode.Account) {
- try {
- unlockView = new AccountUnlockScreen(
- mContext,
- mConfiguration,
- mUpdateMonitor,
- mKeyguardScreenCallback,
- mLockPatternUtils);
- } catch (IllegalStateException e) {
- Log.i(TAG, "Couldn't instantiate AccountUnlockScreen"
- + " (IAccountsService isn't available)");
-
-
-
-
-
-
-
-
-
-
- return createUnlockScreenFor(UnlockMode.Pattern);
- }
- } else if (unlockMode == UnlockMode.Password) {
-
- unlockView = new PasswordUnlockScreen(
- mContext,
- mConfiguration,
- mLockPatternUtils,
- mUpdateMonitor,
- mKeyguardScreenCallback);
- } else {
- throw new IllegalArgumentException("unknown unlock mode " + unlockMode);
- }
- initializeTransportControlView(unlockView);
- initializeFaceLockAreaView(unlockView);
-
- mUnlockScreenMode = unlockMode;
- return unlockView;
- }
- ...
在此,LockScreen或者UnlockScreen就創(chuàng)建出來(lái)了,當(dāng)然,只是創(chuàng)建了相應(yīng)對(duì)象,還得再顯示。
------>再次回到KeyguardViewManager類的show方法,在執(zhí)行完該方法中的的mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext,
mUpdateMonitor, this)代碼流程后,接著執(zhí)行mKeyguardView.show(),即調(diào)用KeyguardViewBase的實(shí)現(xiàn)類LockPatternKeyguardView的show方法,如下:
-
- public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback,
- KeyguardUpdateMonitor.InfoCallback {
- ...
- @Override
- public void show() {
-
-
-
- if (mMode == Mode.LockScreen) {
-
- ((KeyguardScreen) mLockScreen).onResume();
- } else {
- ((KeyguardScreen) mUnlockScreen).onResume();
- }
-
- if (mLockPatternUtils.usingBiometricWeak() &&
- mLockPatternUtils.isBiometricWeakInstalled() && !mHasOverlay) {
-
-
-
-
- showFaceLockArea();
- } else {
- hideFaceLockArea();
- }
- }
- ...
- }
這樣,LockScreen或者UnlockScreen就顯示出來(lái)了,我們?cè)賮?lái)看看LockScreen的onResume()方法的實(shí)現(xiàn),代碼如下:
-
- class LockScreen extends LinearLayout implements KeyguardScreen {
- ...
-
- public void onResume() {
- mStatusViewManager.onResume();
- postDelayed(mOnResumePing, ON_RESUME_PING_DELAY);
- }
- ...
- }
對(duì)于LockScreen或者UnlockScreen的界面布局和View等可視化UI界面時(shí)如何畫(huà)出來(lái)的,具體可參考LockScreen類的實(shí)現(xiàn),UnlockScreen可參考的類:PatternUnlockScreen、SimPukUnlockScreen、SimUnlockScreen、AccountUnlockScreen、PasswordUnlockScreen。有興趣的讀者可自行去研究。
小結(jié):
這篇文章只是講解手機(jī)開(kāi)機(jī)啟動(dòng)時(shí),繪制鎖屏的流程,至于通過(guò)power鍵點(diǎn)亮,點(diǎn)暗鎖屏,解鎖,鎖屏,LockScreen或者UnlockScreen的UI界面可視化的實(shí)現(xiàn)等等的分析,有時(shí)間再去深究。
但,萬(wàn)變不離其宗,鎖屏的核心類在于KeyguardViewMediator,該類提供了一些接口,由PhoneWindowManager去訪問(wèn)控制Keyguard,而它的初始化是在PhoneWindowManager的init()函數(shù)中創(chuàng)建的。也就是在我們上面分析的代碼中,在執(zhí)行mPolicy.systemReady()時(shí)(由PhoneWindowManage調(diào)用r),已經(jīng)創(chuàng)建了KeyguardViewMediator。所以,分析好該類是很重要的。
OK,個(gè)人對(duì)鎖屏開(kāi)機(jī)繪制流程的粗略分析就到這里了,春節(jié)即將來(lái)臨,在此祝愿所有身處挨踢行業(yè)的同志們,回家過(guò)個(gè)好年?。?/span>