最近大体看了一下android源码锁屏模块,顺便把自己的收获在此记录下来,希望对研究锁屏的同行们有所帮助(对于锁屏模块,本人也没什么时间去真正的深究,只是摸清了个大概,若有奇异和错误之处,恳请指出)
好了,废话不多说了。
Android源码模块锁屏大体分为两种:
1.LockScreen: 系统默认的锁屏,就是我们所常见的系统原生波纹解锁(涉及MultiWaveView视图类)。如下图:
2.UnlockScreen: 进入手机的设置----->安全----->屏幕锁定。在列表中将看到的可选择项:图案,PIN,密码等锁屏都归为UnlockScreen。(可选择任意一项切换锁屏)
锁屏相关源码所在路径:
1.锁屏模块的框架源码所在路径为:frameworks\base\policy\src\com\android\internal\policy\impl(本文所涉及的代码都在这个目录里)
2.相关的锁屏自定义View类及与其关联类的源码所在路径为:frameworks\base\core\java\com\android\internal\widget
开机绘制锁屏流程代码分析:
手机开机时,在SystemServer类的init2()方法中会启动线程类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);
}
...
}
}
------>上述代码中的wm为WindowManagerService的引用,所以,wm.systemReady()为调用WindowManagerService的systemReady()方法,如下代码:
public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager(); ... public void systemReady() { mPolicy.systemReady(); } ... }
------>WindowManagerPolicy的实现类为PhoneWindowManager,所以,接着调用到PhoneWindowManager的systemReady,如下:
public class PhoneWindowManager implements WindowManagerPolicy { KeyguardViewMediator mKeyguardMediator; ... //手机开机后执行 public void systemReady() { // tell the keyguard mKeyguardMediator.onSystemReady(); //进行待机锁屏及解锁逻辑 android.os.SystemProperties.set("dev.bootcomplete", "1"); synchronized (mLock) { updateOrientationListenerLp(); mSystemReady = true; mHandler.post(new Runnable() { public void run() { updateSettings(); } }); } } ... }
------>接着,调用到KeyguardViewMediator类的onSystemReady()方法如下:
public class KeyguardViewMediator implements KeyguardViewCallback, KeyguardUpdateMonitor.InfoCallback, KeyguardUpdateMonitor.SimStateCallback { ... /** * Let us know that the system is ready after startup. */ //开机显示锁屏入口 public void onSystemReady() { synchronized (this) { if (DEBUG) Log.d(TAG, "onSystemReady"); mSystemReady = true; doKeyguardLocked(); } } ... }
------>调用KeyguardViewMediator.doKeyguardLocked方法,在该方法中,先执行一些条件判断,若满足直接返回。若不直接返回,则紧接着调用KeyguardViewMediator. showLocked方法,代码如下:
... /** * Send message to keyguard telling it to show itself * @see #handleShow() */ private void showLocked() { if (DEBUG) Log.d(TAG, "showLocked"); // ensure we stay awake until we are finished displaying the keyguard mShowKeyguardWakeLock.acquire(); //确保屏幕处于唤醒状态 Message msg = mHandler.obtainMessage(SHOW); mHandler.sendMessage(msg); } ...
----->通过handler发送消息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. */ //Handler对象 , 异步处理 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; } } }; ...
------>当case SHOW:时,调用 handleShow方法,如下:
private KeyguardViewManager mKeyguardViewManager; ... /** * Handle message sent by {@link #showLocked}. * @see #SHOW */ //显示锁屏界面 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) { } // Do this at the end to not slow down display of the keyguard. playSounds(true); mShowKeyguardWakeLock.release(); } } ...
----->接着调用KeyguardViewManager的show方法。KeyguardViewManager.show()中,会对KeyguardViewHost(mKeyguardHost)和LockPatternKeyguardView(mKeyguardView)是否为空进行判断:
1).若KeyguardViewHost为空,则创建KeyguardViewHost,同时设置更新其相关的布局参数。然后将KeyguardViewHost对象添加到WindowManagerImpl中。
2). 若LockPatternKeyguardView为空,创建LockPatternKeyguardView对象,通过调用LockPatternKeyguardViewProperties.createKeyguardView()创建。同时为它设置回调。然后将创建得到的对象添加到KeyguardViewHost。
代码如下:
public class KeyguardViewManager implements KeyguardWindowController { ... private FrameLayout mKeyguardHost; //该ViewGroup作为顶层View,作为WindowManager添加至窗口 private KeyguardViewBase mKeyguardView; //具体窗口内容。 //以上两种的关系相当于DecorView和我们Activity内设置的资源文件一样 private final KeyguardViewProperties mKeyguardViewProperties; ... /** * Show the keyguard. Will handle creating and attaching to the view manager * lazily. */ //显示锁屏界面 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..."); //创建KeyguardViewHost(FrameLayout) 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 /*| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR*/ ; 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; //添加KeyguardViewHost 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..."); /*创建锁屏视图,即创建一个LockPatternKeyguardView对象(FrameLayout)。在创建LockPatternKeyguardView * 对象的同时,其构造方法中会调用getInitialMode()得到初始化的状态Mode(Lock or unLock) */ 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(FrameLayout) mKeyguardHost.addView(mKeyguardView, lp); if (mScreenOn) { //调用LockPatternKeyguardView的show mKeyguardView.show(); } } // Disable aspects of the system/status/navigation bars that are not appropriate or // useful for the lockscreen but can be re-shown by dialogs or SHOW_WHEN_LOCKED activities. // Other disabled bits are handled by the KeyguardViewMediator talking directly to the // status bar service. 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(); } ... }
------>在上面的代码中,当KeyguardViewHost为空时,首先会调用KeyguardViewProperties的实现类LockPatternKeyguardViewProperties的createKeyguardView方法,来构造一个LockPatternKeyguardView对象,如下:
public class LockPatternKeyguardViewProperties implements KeyguardViewProperties {
...
//创建一个LockPatternKeyguardView对象
public KeyguardViewBase createKeyguardView(Context context,
KeyguardUpdateMonitor updateMonitor,
KeyguardWindowController controller) {
return new LockPatternKeyguardView(context, updateMonitor,
mLockPatternUtils, controller);
}
...
}
------->而在LockPatternKeyguardView的构造函数中,有如下调用(以下的流程代码实现均在LockPatternKeyguardView中处理):
/** * @param context Used to inflate, and create views. * @param updateMonitor Knows the state of the world, and passed along to each * screen so they can use the knowledge, and also register for callbacks * on dynamic information. * @param lockPatternUtils Used to look up state of lock pattern. */ public LockPatternKeyguardView( Context context, KeyguardUpdateMonitor updateMonitor, LockPatternUtils lockPatternUtils, KeyguardWindowController controller) { ... updateScreen(getInitialMode(), false); ... }
----->getInitialMode()得到当前锁屏模式(lock or unlock),代码如下:
... /** * Given the current state of things, what should be the initial mode of * the lock screen (lock or unlock). */ //得到初始化的状态Mode (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),该函数的实现如下:
... //根据参数(Lock/unLock),判断显示为LockScreen或者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; // Re-create the lock screen if necessary if (mode == Mode.LockScreen || mShowLockBeforeUnlock) { if (force || mLockScreen == null) { //重构LockScreen recreateLockScreen(); } } // Re-create the unlock screen if necessary. This is primarily required to properly handle // SIM state changes. This typically happens when this method is called by reset() if (mode == Mode.UnlockScreen) { //获取UnlockScreen的具体解锁项,如密码锁(Password)或pin锁;枚举类UnlockMode定义了几种不同的Unlock解锁; final UnlockMode unlockMode = getUnlockMode(); if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { //重构unLock解锁 recreateUnlockScreen(unlockMode); } } // visibleScreen should never be null final View goneScreen = (mode == Mode.LockScreen) ? mUnlockScreen : mLockScreen; final View visibleScreen = (mode == Mode.LockScreen) ? mLockScreen : mUnlockScreen; // do this before changing visibility so focus isn't requested before the input // flag is set 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(); //隐藏被切换掉的锁(Lock or unLock) } if (visibleScreen.getVisibility() != View.VISIBLE) { ((KeyguardScreen) visibleScreen).onResume();//显示切换得到的锁(Lock or unLock) } } 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)中,对传进来的参数Mode进行对等判断:
1). 若为LockScreen模式锁屏,则如下:
// Re-create the lock screen if necessary
if (mode == Mode.LockScreen || mShowLockBeforeUnlock) {
if (force || mLockScreen == null) {
//重构LockScreen
recreateLockScreen();
}
}
----->然后调用到LockPatternKeyguardView.recreateLockScreen(),在该函数中,首先会对LockScreen进行判断,若之前已存在该对象,则进行移除。然后接着再重新调用createLockScreen()构建LockScreen对象。然后将该对象添加到LockPatternKeyguardView中。createLockScreen()的代码如下:
... //创建lockScreen View createLockScreen() { View lockView = new LockScreen( mContext, mConfiguration, mLockPatternUtils, mUpdateMonitor, mKeyguardScreenCallback); initializeTransportControlView(lockView); return lockView; } ...
2).若为UnlockScreen模式锁屏,则如下:
// Re-create the unlock screen if necessary. This is primarily required to properly handle // SIM state changes. This typically happens when this method is called by reset() if (mode == Mode.UnlockScreen) { //获取UnlockScreen的具体解锁项,如密码锁(Password)或pin锁;枚举类UnlockMode定义了几种不同的Unlock解锁; final UnlockMode unlockMode = getUnlockMode(); if (force || mUnlockScreen == null || unlockMode != mUnlockScreenMode) { //重构unLock解锁 recreateUnlockScreen(unlockMode); } }
----->然后调用到LockPatternKeyguardView.recreateUnlockScreen(unlockMode),在该函数中,进行的处理和recreateLockScreen函数中的处理原则基本上一致。则调用createUnlockScreen(unlockMode)时,会根据unlockMode的不同创建相应的UnlockScreen具体解锁项。
recreateUnlockScreen如下代码:
... //重新构建UnlockScreen private void recreateUnlockScreen(UnlockMode unlockMode) { if (mUnlockScreen != null) { ((KeyguardScreen) mUnlockScreen).onPause(); ((KeyguardScreen) mUnlockScreen).cleanUp(); //mUnlockScreen不为空,则移除UnlockScreen removeView(mUnlockScreen); } mUnlockScreen = createUnlockScreenFor(unlockMode); mUnlockScreen.setVisibility(View.INVISIBLE); //将UnlockScreen添进LockPatternKeyguardView addView(mUnlockScreen); } ...
----->接着调用createUnlockScreenFor方法,在该方法中会根据传进来的参数UnlockMode(定义UnlockScreen可选项的枚举类)判断,来决定创建启用对应的UnlockScreen,代码实现如下:
... //根据不同的Unlock Mode , 创建不同的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) { //启动PIN解锁(手机设置中可见切换) 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)"); // TODO: Need a more general way to provide a // platform-specific fallback UI here. // For now, if we can't display the account login // unlock UI, just bring back the regular "Pattern" unlock mode. // (We do this by simply returning a regular UnlockScreen // here. This means that the user will still see the // regular pattern unlock UI, regardless of the value of // mUnlockScreenMode or whether or not we're in the // "permanently locked" state.) 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); // Only shows view if FaceLock is enabled mUnlockScreenMode = unlockMode; return unlockView; } ...
在此,LockScreen或者UnlockScreen就创建出来了,当然,只是创建了相应对象,还得再显示。
------>再次回到KeyguardViewManager类的show方法,在执行完该方法中的的mKeyguardView = mKeyguardViewProperties.createKeyguardView(mContext, mUpdateMonitor, this)代码流程后,接着执行mKeyguardView.show(),即调用KeyguardViewBase的实现类LockPatternKeyguardView的show方法,如下:
//该类作为LockScreen和UnLockScreen界面的载体,控制显示哪个界面 public class LockPatternKeyguardView extends KeyguardViewBase implements Handler.Callback, KeyguardUpdateMonitor.InfoCallback { ... @Override public void show() { /*判断锁屏模式(当然,调用该方法之前已经创建LockPatternKeyguardView对象, * 即已调用getInitialMode()获得了Mode),根据结果显示锁屏。 */ if (mMode == Mode.LockScreen) { //调用onResume显示锁屏 ((KeyguardScreen) mLockScreen).onResume(); } else { ((KeyguardScreen) mUnlockScreen).onResume(); } if (mLockPatternUtils.usingBiometricWeak() && mLockPatternUtils.isBiometricWeakInstalled() && !mHasOverlay) { // Note that show() gets called before the screen turns off to set it up for next time // it is turned on. We don't want to set a timeout on the FaceLock area here because it // may be gone by the time the screen is turned on again. We set the timout when the // screen turns on instead. showFaceLockArea(); //显示人脸解锁区域 } else { hideFaceLockArea(); //隐藏人脸解锁区域 } } ... }
这样,LockScreen或者UnlockScreen就显示出来了,我们再来看看LockScreen的onResume()方法的实现,代码如下:
//手机默认的解锁实现类 class LockScreen extends LinearLayout implements KeyguardScreen { ... //处理LockScreen的显示 public void onResume() { mStatusViewManager.onResume(); postDelayed(mOnResumePing, ON_RESUME_PING_DELAY); } ... }
对于LockScreen或者UnlockScreen的界面布局和View等可视化UI界面时如何画出来的,具体可参考LockScreen类的实现,UnlockScreen可参考的类:PatternUnlockScreen、SimPukUnlockScreen、SimUnlockScreen、AccountUnlockScreen、PasswordUnlockScreen。有兴趣的读者可自行去研究。
小结:
这篇文章只是讲解手机开机启动时,绘制锁屏的流程,至于通过power键点亮,点暗锁屏,解锁,锁屏,LockScreen或者UnlockScreen的UI界面可视化的实现等等的分析,有时间再去深究。
但,万变不离其宗,锁屏的核心类在于KeyguardViewMediator,该类提供了一些接口,由PhoneWindowManager去访问控制Keyguard,而它的初始化是在PhoneWindowManager的init()函数中创建的。也就是在我们上面分析的代码中,在执行mPolicy.systemReady()时(由PhoneWindowManage调用r),已经创建了KeyguardViewMediator。所以,分析好该类是很重要的。
OK,个人对锁屏开机绘制流程的粗略分析就到这里了,春节即将来临,在此祝愿所有身处挨踢行业的同志们,回家过个好年!!