浅析android锁屏开机绘制流程(基于android4.0源码分析)

来源:互联网 发布:淘宝最美女模特 编辑:程序博客网 时间:2024/05/16 00:36

    

      最近大体看了一下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,个人对锁屏开机绘制流程的粗略分析就到这里了,春节即将来临,在此祝愿所有身处挨踢行业的同志们,回家过个好年!!

原创粉丝点击