2018-01-14Android 6.0 SystemUI 锁屏流程解析

Android 6.0 SystemUI 锁屏流程解析

谈到锁屏我们先来简单看下systemUI的启动流程

SystemUI常驻于系统,通过Service实现,关键service:SystemUIService是在SystemServer.java中启动。

Android的启动分为内核启动,android启动,Launcher启动,我们的SystemServer就处于Android启动中,SystemUI的启动以下是大致流程:init->ServiceManager->Zygote->SystemServer->SystemUIService-->SystemUIApplication-->SystemUI.start(KeyguardViewMeditor,Recents等SytsemUI子类开始各司其职的正常工作起来)

SystemUI具体的启动流程代码可以参考博客。

设计代码

frameworks/base/packages/Keyguard

frameworks/base/packages/SystemUI

frameworks/base/policy/src/com/android/internal/policy/impl/keyguard/ KeyguardServiceWrapper.java KeyguardServiceDelegate.java frameworks/base/core/java/android/app/keyguardManager.java packages/apps/Settings/src/com/android/settings/ChooseLockGeneric.java SecuritySettings.java

锁屏分类

那么锁屏界面是怎样加载到widnow显示出来的呢?首先需要明确的是6.0分为两类锁屏(非安全锁屏<滑动锁屏>和安全锁屏<图案和pin等>)

1.非安全锁屏,称之为notification keyguard,这个类型的keyguard 已经和statusbar融为一体,可以通过PhoneStatusBar.java对象直接进行控制;

2.安全锁屏,比如密码,图案,PIN码,PUK码等锁屏的锁屏界面,通过keyguardBouncer.java进行控制

锁屏加载流程


非安全锁屏加载流程

首先非安全锁屏界面,是NotificationPanelView的一部分,在SystemUI启动SystemUI.start就已经加载,看下SystemUI开机启动流程图

因为这里重点是锁屏,所以我们从PhoneStatusBar.start()开启看。

PhoneStatusBar.start会调用父类BaseStatusBar的start(),继续调用PhoneStatusBar的createAndAddWindow(),然后继续调用addStatusBarWindow来创建通知锁屏等StatusBarWindowView并加到window上。

非安全锁屏是NotificationPanelView的一部分,而NotificationPanelView又是StatusBarWindowView的一部分,所以这样就已经将非安全模式加载好了,至于显示还是隐藏就只是NotificationPanelView界面调整的问题了,具体的View层级和控制代码量太多,暂不做深入分析

private void addStatusBarWindow() { makeStatusBarView(); mStatusBarWindowManager = new StatusBarWindowManager(mContext); mRemoteInputController = new RemoteInputController(mStatusBarWindowManager, mHeadsUpManager); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); }

安全锁屏加载流程

安全锁屏SystemUI启动时准备

上面还只是加载了非安全锁屏界面,那安全锁屏界面呢?实际上安全锁屏界面也会加载到StatusBarWindowView,只不过是动态加载和移除,并不是直接放在布局里初始化加载,我们简单看下锁屏UI层级

在PhoneStatusBar.start()方法里加载完StatusBarWindowView后,还会调用startKeyGuard()来安全锁屏的一些初始化准备工作,这里关注的是将StatusBarWindowView作为属性赋值给安全锁屏的操控类KeyguardBoncer

public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
        DragDownHelper.DragDownCallback, ActivityStarter, OnUnlockMethodChangedListener,
        HeadsUpManager.OnHeadsUpChangedListener {
    @Override
    public void start() {
        super.start(); // calls createAndAddWindows()
        startKeyguard();
     }

    private void startKeyguard() {
        KeyguardViewMediator keyguardViewMediator = getComponent(KeyguardViewMediator.class);
        //-----这里的mStatusBarWindow就是StatusBarWindowView
        mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
                mStatusBarWindow, mStatusBarWindowManager, mScrimController);
        mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback();
    }
}

public class KeyguardViewMediator extends SystemUI {
    public StatusBarKeyguardViewManager registerStatusBar(PhoneStatusBar phoneStatusBar,
            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
            ScrimController scrimController) {
        //-----这里的container就是StatusBarWindowView       
        mStatusBarKeyguardViewManager.registerStatusBar(phoneStatusBar, container,
                statusBarWindowManager, scrimController);
        return mStatusBarKeyguardViewManager;
    }
}
 
public class StatusBarKeyguardViewManager {
    public void registerStatusBar(PhoneStatusBar phoneStatusBar,
            ViewGroup container, StatusBarWindowManager statusBarWindowManager,
            ScrimController scrimController) {
        mPhoneStatusBar = phoneStatusBar;
        mContainer = container;
        mStatusBarWindowManager = statusBarWindowManager;
        mScrimController = scrimController;
        mBouncer = new KeyguardBouncer(mContext, mViewMediatorCallback, mLockPatternUtils,
                mStatusBarWindowManager, container);
        mKeyguardMusicManager = KeyguardMusicManager.getInstance(mContext, this);
    }
}

public class KeyguardBouncer {
    public KeyguardBouncer(Context context, ViewMediatorCallback callback,
            LockPatternUtils lockPatternUtils, StatusBarWindowManager windowManager,
            ViewGroup container) {
        mContext = context;
        mCallback = callback;
        mLockPatternUtils = lockPatternUtils;
        mContainer = container;//-----这样就将StatusBarWindowView作为属性赋值给安全锁屏的操控类
        mWindowManager = windowManager;
    }
}

安全锁屏开机展示流程

时序图

到现在为止还只是StatusBarWindowView与KeyguardBouncer关联,那安全锁屏界面到底是什么时候加载到StatusBarWindowView从而显示给我们呢?实际上我们前面也说了,安全锁屏界面其实是动态的加载和移除的,从未上锁到上锁就会addView,完成全部解锁就会removeView,比如开机完成后就会上锁,下面我们来分析下开机展示安全锁屏流程,首先看下时序图:



代码流程

开机启动流程其实也很复杂,但是本文重点在于KeyGuard锁屏的展示,所以我们从开机启动调用到PhoneWindowManager的SystemReady()和SystemReady()和SystemBooted()方法开始分析。

systemReady()调用systemBooted()之前,至于具体的调用流程这里不做分析,大致也是SystemServer.java中main函数会调用startOtherService()方法跟下去:

那么现在看下去PhoneWindowManager的systemReady()和systemBooted()这两个方法

public class PhoneWindowManager implements WindowManagerPolicy {
    @Override
    public void systemReady() {
        mKeyguardDelegate = new KeyguardServiceDelegate(mContext);
        mKeyguardDelegate.onSystemReady();
        boolean bindKeyguardNow;
        synchronized (mLock) {
            bindKeyguardNow = mDeferBindKeyguard;
            if (bindKeyguardNow) {
                // systemBooted ran but wasn't able to bind to the Keyguard, we'll do it now.
                mDeferBindKeyguard = false;
            }
        }
        if (bindKeyguardNow) {
            mKeyguardDelegate.bindService(mContext);
            mKeyguardDelegate.onBootCompleted();
        }
    }
   
    @Override
    public void systemBooted() {
        
        boolean bindKeyguardNow = false;
        synchronized (mLock) {
            // Time to bind Keyguard; take care to only bind it once, either here if ready or
            // in systemReady if not.
            if (mKeyguardDelegate != null) {
                bindKeyguardNow = true;
            } else {
                // Because mKeyguardDelegate is null, we know that the synchronized block in
                // systemReady didn't run yet and setting this will actually have an effect.
                mDeferBindKeyguard = true;
            }
        }
        if (bindKeyguardNow) {
            mKeyguardDelegate.bindService(mContext);
            mKeyguardDelegate.onBootCompleted();
        }
 }

看代码可知,systemReady()方法里初始化KeyguardServiceDeleGate,但还不能bindService,等到systemBooted()时才能bindService,下面bindService做了些什么

public class KeyguardServiceDelegate {
    protected KeyguardServiceWrapper mKeyguardService;

    public void bindService(Context context) {
        Intent intent = new Intent();
        //-----config_keyguardComponent就是com.android.systemui/com.android.systemui.keyguard.KeyguardService
        final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                resources.getString(com.android.internal.R.string.config_keyguardComponent));
        intent.setComponent(keyguardComponent);
        if (!context.bindServiceAsUser(intent, mKeyguardConnection,
                Context.BIND_AUTO_CREATE, UserHandle.OWNER)) {}
    }

    private final ServiceConnection mKeyguardConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mKeyguardService = new KeyguardServiceWrapper(mContext,
                    IKeyguardService.Stub.asInterface(service));
            if (mKeyguardState.systemIsReady) {
                // If the system is ready, it means keyguard crashed and restarted.
                mKeyguardService.onSystemReady();//-----前面调用systemReady,所以这里成立
                // This is used to hide the scrim once keyguard displays.
                mKeyguardService.onStartedWakingUp()
                mKeyguardService.onScreenTurningOn(
                        new KeyguardShowDelegate(mDrawnListenerWhenConnect));
                mKeyguardService.onScreenTurnedOn();
                mDrawnListenerWhenConnect = null;
            }
            if (mKeyguardState.bootCompleted) {
                mKeyguardService.onBootCompleted();
            }
            if (mKeyguardState.occluded) {
                mKeyguardService.setOccluded(mKeyguardState.occluded);
            }
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            if (DEBUG) Log.v(TAG, "*** Keyguard disconnected (boo!)");
            mKeyguardService = null;
        }

    };
 }

因为config_keyguardComponent就是com.android.systemui/com.andoid.systemui.keyguard.KeyguardService,所以IKeyguardService.Stub.asInterface(service)就是KeyguardService里的private final IKeyguardService.Stub mBinder,也就是KeyguardServiceWrapper里的private IKeyguardService mService,所以接着调用onSystemReady()

public class KeyguardServiceWrapper implements IKeyguardService {
    private IKeyguardService mService;

    public KeyguardServiceWrapper(Context context, IKeyguardService service) {
        mService = service;
    }

    @Override // Binder interface
    public void onSystemReady() {
        try {
            mService.onSystemReady();
        } catch (RemoteException e) {
            Slog.w(TAG , "Remote Exception", e);
        }
    }
}

于是再走到KeyguardService.mBinder.onSystemReady()

public class KeyguardService extends Service {
    private KeyguardViewMediator mKeyguardViewMediator;
    private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {
        @Override // Binder interface
        public void onSystemReady() {
            checkPermission();
            mKeyguardViewMediator.onSystemReady();
        }
    }
}

终于走到我们锁屏模块最关键的调度类KeyguardViewMediator,功能上负责处理keyguard试图的事件,锁屏事件的入口,下面继续KeyguardViewMediator的doKeyguardLocked()

public class KeyguardViewMediator extends SystemUI {
    public void onSystemReady() {
            doKeyguardLocked(null);
    }

    private void doKeyguardLocked(Bundle options) {
        showLocked(options);
    }

    private void showLocked(Bundle options) {
        if (DEBUG) Log.d(TAG, "showLocked");
        // ensure we stay awake until we are finished displaying the keyguard
        mShowKeyguardWakeLock.acquire();
        Message msg = mHandler.obtainMessage(SHOW, options);
        mHandler.sendMessage(msg);
    }

    private Handler mHandler = new Handler(Looper.myLooper(), null, true /*async*/) {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SHOW:
                    handleShow((Bundle) msg.obj);
                    break;
            }
        }
    };

    private void handleShow(Bundle options) {
            mStatusBarKeyguardViewManager.show(options);
    }
   
}

通过代码可知,最后将show动作交给StatusBarkeyguardViewManager来处理,实际上这类直接锁屏相关动作最后都会交给StatusbarKeyguardViewManager处理,StatusBarKeyguardViewManager就是keyguard的视图管理者,包括非安全锁屏和安全锁屏,接着往下看

public class StatusBarKeyguardViewManager {
     private PhoneStatusBar mPhoneStatusBar;
     private KeyguardBouncer mBouncer;
     /**
     * Show the keyguard.  Will handle creating and attaching to the view manager
     * lazily.
     */
    public void show(Bundle options) {
        mShowing = true;
        mStatusBarWindowManager.setKeyguardShowing(true);
        mScrimController.abortKeyguardFadingOut();
        reset();//-----show和reset动作都会调用reset
        mKeyguardMusicManager.start();
    }

    /**
     * Reset the state of the view.
     */
    public void reset() {
        if (mShowing) {
            if (mOccluded) {
                mPhoneStatusBar.hideKeyguard();
                mPhoneStatusBar.stopWaitingForKeyguardExit();
                mBouncer.hide(false /* destroyView */);
            } else {
                showBouncerOrKeyguard();//-----显示安全锁屏界面还是先显示非安全锁屏界面
            }
            KeyguardUpdateMonitor.getInstance(mContext).sendKeyguardReset();
            updateStates();
        }
    }

    /**
     * Shows the notification keyguard or the bouncer depending on
     * {@link KeyguardBouncer#needsFullscreenBouncer()}.
     */
    private void showBouncerOrKeyguard() {
        if (mBouncer.needsFullscreenBouncer()) {

            // The keyguard might be showing (already). So we need to hide it.
            mPhoneStatusBar.hideKeyguard();
            mBouncer.show(true /* resetSecuritySelection */);
        } else {
            mPhoneStatusBar.showKeyguard();
            mBouncer.hide(false /* destroyView */);
            mBouncer.prepare();
        }
    }
}

在showBouncerOrKeyguard方法里mPhoneStatusBar.hideKeyguard()和mPhoneStatusBar.showKeyguard;控制的是非安全锁,而mBoncer.show(true)和mBoncer.hide(false)控制的是安全锁屏,也就是说非安全锁屏和安全锁屏在这里开始分别由PhoneStatusBar和KeyguardBouncer管理,前面说了非安全锁屏这里不做升入分析,下面重点看安全锁屏,安全锁屏界面KeyguardHostView作为KeyguardBouncer的属性直接被操控,而要不要先显示非安全锁屏是根据锁屏模式来的,由于锁屏情况太多现在假设是图案解锁,具体在往下来,根据目前场景来看是会走到

/**
 * A class which manages the bouncer on the lockscreen.
 */
public class KeyguardBouncer {

    private KeyguardHostView mKeyguardView;
    /**
     * @return True if and only if the security method should be shown before showing the
     * notifications on Keyguard, like SIM PIN/PUK.
     */
    public boolean needsFullscreenBouncer() {
        ensureView();//-----a
        if (mKeyguardView != null) {
            SecurityMode mode = mKeyguardView.getSecurityMode();
            return mode == SecurityMode.SimPin || mode == SecurityMode.SimPuk;//-----c
        }
        return false;
    }

    public void show(boolean resetSecuritySelection) {//-----实际上显示、重置、移除动作都会调用到
        ensureView();//----确保安全锁屏界面有创建并添加到StatusBarWindowView上,并且安全界面初始化时是不可见的INVISIBLE

        if (resetSecuritySelection) {//-----是否需要重置安全界面
            // showPrimarySecurityScreen() updates the current security method. This is needed in
            // case we are already showing and the current security method changed.
            mKeyguardView.showPrimarySecurityScreen();//-----d
        }
        if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {//-----mRoot是安全锁屏界面,当已是可见是return,比如重置
            return;
        }
        // Try to dismiss the Keyguard. If no security pattern is set, this will dismiss the whole
        // Keyguard. If we need to authenticate, show the bouncer.
        if (!mKeyguardView.dismiss()) {//-----试图移除锁屏界面,比如刚上锁,安全界面还不可见//-----e
            mShowingSoon = true; // Split up the work over multiple frames.
            DejankUtils.postAfterTraversal(mShowRunnable);//-----安全界面设置成可见VISIBLE//-----f
        }
    }

    private final Runnable mShowRunnable = new Runnable() {
        @Override
        public void run() {
            mRoot.setVisibility(View.VISIBLE);
            mKeyguardView.onResume();
            showPromptReason(mBouncerPromptReason);
            mKeyguardView.startAppearAnimation();
            mShowingSoon = false;
            mKeyguardView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
        }
    };

    private void ensureView() {
        if (mRoot == null) {//-----安全界面跟布局,一般无锁到有锁初始化,完全完成解锁时置空
            inflateView();//-----b
        }
    }

    private void inflateView() {
        removeView();
        mRoot = (ViewGroup) LayoutInflater.from(mContext).inflate(R.layout.keyguard_bouncer, null);
        mKeyguardView = (KeyguardHostView) mRoot.findViewById(R.id.keyguard_host_view);
        mKeyguardView.setLockPatternUtils(mLockPatternUtils);
        mKeyguardView.setViewMediatorCallback(mCallback);
        mContainer.addView(mRoot, mContainer.getChildCount());
        mRoot.setVisibility(View.INVISIBLE);
        mRoot.setSystemUiVisibility(View.STATUS_BAR_DISABLE_HOME);
    }

}

接着看mKeyguardView.showPrimarySecurityScreen(),KeyguardHostView是安全锁屏主界面,实现了SecrityCallBack接口,其他地方用到的SeurityCakkback其实就是KeyguardHostview

public class KeyguardHostView extends FrameLayout implements SecurityCallback {
    private KeyguardSecurityContainer mSecurityContainer;
        /**
     * Called when the view needs to be shown.
     */
    public void showPrimarySecurityScreen() {
        if (DEBUG) Log.d(TAG, "show()");
        mSecurityContainer.showPrimarySecurityScreen(false);
    }
}

KeyguardSecurityContainer,安全锁屏View的容,会具体根据安全模式展示不同的View,继续往下面

public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSecurityView {
    private KeyguardSecurityViewFlipper mSecurityViewFlipper;//安全view的父布局

    /**
     * Shows the primary security screen for the user. This will be either the multi-selector
     * or the user's security method.
     * @param turningOff true if the device is being turned off
     */
    void showPrimarySecurityScreen(boolean turningOff) {
        SecurityMode securityMode = mSecurityModel.getSecurityMode();//----获取安全模式
        if (DEBUG) Log.v(TAG, "showPrimarySecurityScreen(turningOff=" + turningOff + ")");
        showSecurityScreen(securityMode);
    }

    private void showSecurityScreen(SecurityMode securityMode) {
        if (DEBUG) Log.d(TAG, "showSecurityScreen(" + securityMode + ")");

        if (securityMode == mCurrentSecuritySelection) return;

        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
        KeyguardSecurityView newView = getSecurityView(securityMode);

        // Emulate Activity life cycle
        if (oldView != null) {
            oldView.onPause();
            oldView.setKeyguardCallback(mNullCallback); // ignore requests from old view
        }
        if (securityMode != SecurityMode.None) {
            newView.onResume(KeyguardSecurityView.VIEW_REVEALED);
            newView.setKeyguardCallback(mCallback);
        }
        // Find and show this child.
        final int childCount = mSecurityViewFlipper.getChildCount();

        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        for (int i = 0; i < childCount; i++) {
            if (mSecurityViewFlipper.getChildAt(i).getId() == securityViewIdForMode) {
                mSecurityViewFlipper.setDisplayedChild(i);
                break;
            }
        }

        mCurrentSecuritySelection = securityMode;
        mSecurityCallback.onSecurityModeChanged(securityMode,
                securityMode != SecurityMode.None && newView.needsInput());
    }

    private KeyguardSecurityView getSecurityView(SecurityMode securityMode) {
        final int securityViewIdForMode = getSecurityViewIdForMode(securityMode);
        KeyguardSecurityView view = null;
        final int children = mSecurityViewFlipper.getChildCount();
        for (int child = 0; child < children; child++) {
            if (mSecurityViewFlipper.getChildAt(child).getId() == securityViewIdForMode) {
                view = ((KeyguardSecurityView)mSecurityViewFlipper.getChildAt(child));
                break;
            }
        }
        int layoutId = getLayoutIdFor(securityMode);
        if (view == null && layoutId != 0) {
            final LayoutInflater inflater = LayoutInflater.from(mContext);
            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
            View v = inflater.inflate(layoutId, mSecurityViewFlipper, false);
            mSecurityViewFlipper.addView(v);//----将安全view添加到父布局<span></span>KeyguardSecurityViewFlipper从而到<span></span>KeyguardSecurityContainer上
            updateSecurityView(v);
            view = (KeyguardSecurityView)v;
        }

        return view;
    }

}

到目前位置通过mSercutityViewFliper.addView(v);最终将安全view添加到StatusBarWindowView,但是安全锁屏跟布局还是不可见的,所以代码走到KeyguardBouncer的处,那么mKeyguardView.dismiss()又做了什么呢,继续往下跟

public class KeyguardHostView extends FrameLayout implements SecurityCallback {
    /**
     *  Dismisses the keyguard by going to the next screen or making it gone.
     *
     *  @return True if the keyguard is done.
     */
    public boolean dismiss() {
        return dismiss(false);
    }

    @Override
    public boolean dismiss(boolean authenticated) {
        return mSecurityContainer.showNextSecurityScreenOrFinish(authenticated);
    }
}

好吧,又是KeyguardSecurityContainer,当前场景下参数未false,继续往下看:

/**
     * Shows the next security screen if there is one.
     * @param authenticated true if the user entered the correct authentication
     * @return true if keyguard is done
     */
    //-----显示下一个安全锁屏界面,参数很重要,参数表示是否经过验证
    boolean showNextSecurityScreenOrFinish(boolean authenticated) {
        if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
        boolean finish = false;
        if (mUpdateMonitor.getUserCanSkipBouncer(
                KeyguardUpdateMonitor.getCurrentUser())) {
            //-----可以跳过安全锁屏,直接完全所有锁屏
            finish = true;
        } else if (SecurityMode.None == mCurrentSecuritySelection) {
            //当前是非安全锁屏(滑动),获取下一个锁屏模式,如果还是非安全锁屏(滑动),直接完全所有锁屏,否则显示下一个安全锁屏界面
            SecurityMode securityMode = mSecurityModel.getSecurityMode();
            if (SecurityMode.None == securityMode) {
                finish = true; // no security required
            } else {
                showSecurityScreen(securityMode); // switch to the alternate security view
            }
        } else if (authenticated) {
            //-----如果是经过验证的,当前的是普通的安全模式,那么完成全部解锁,如果是pin\puk之类的第三类动态的就继续检查下一个锁屏,
            //-----下一个是安全锁屏就继续显示下一个安全锁屏界面,否则完成全部解锁
            switch (mCurrentSecuritySelection) {
                case Pattern:
                case Password:
                case PIN:
                    finish = true;
                    break;

                case SimPin:
                case SimPuk:
                    // Shortcut for SIM PIN/PUK to go to directly to user's security screen or home
                    SecurityMode securityMode = mSecurityModel.getSecurityMode();
                    if (securityMode != SecurityMode.None
                            || !mLockPatternUtils.isLockScreenDisabled(
                            KeyguardUpdateMonitor.getCurrentUser())) {
                        showSecurityScreen(securityMode);
                        /* SPRD:add PIN verify success prompt @{ */
                        KeyguardSecurityView oldView = getSecurityView(mCurrentSecuritySelection);
                        if (oldView != null) {
                            oldView.onPause();
                        }
                        /* @} */
                    } else {
                        finish = true;
                    }
                    break;

                default:
                    Log.v(TAG, "Bad security screen " + mCurrentSecuritySelection + ", fail safe");
                    showPrimarySecurityScreen(false);
                    break;
            }
        }
        if (finish) {
            //-----完成了全部解锁,下面要开始rm安全界面等一些操作,mSecurityCallback就是KeyguardHostView
            mSecurityCallback.finish();
        }
        return finish;
    }

当前场景下都不满足,直接返回false,那么代码继续走到KeyguardBouncer的处,也就是把安全锁屏根布局设置为可见mRoot.setVisibility(View.VISIBLE);最终锁屏控件都已加载到StatusBarWindowView上且可见

锁屏调用入口

其他场景,如解锁,灭屏等按照上面的思路结构都很容易分析就不再赘述,调用入口目前如下几种情况;

1KeyguardSecurityCallBack.dismiss(true)-->KeyguardSecurityContainer.SecurityCallback.dismiss(true)-->实际上对象就是KeyguardHostView.dismiss(true)-->......这中一般是解锁了安全锁屏onClick里

2ViewMeditorCallback-->实际对象就是KeyguardViewMeditor.mViewMeditorCallback

这种一般是应用内直接调用,比如添加手机防盗解锁,受到上锁广播时直接调用showLocked(null)或resetStatLocked()


3、KeyguardServiceDelegate-->绑定KeyguardService       

<permission android:name="com.android.systemui.permission.SELF"             android:protectionLevel="signature" />      

signature:这种权限级别,只有当发请求的应用和接收此请求的应用使用同一签名文件,并且声明了该权限才会授权,并且是默认授权,不会提示用户授权       这种一般是frameworks通过binder服务调用,如开机上锁,灭屏上锁等 

4、通过属性android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUAR                       android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKE    

第三方应用一般因为权限问题通过属性来控制消除非安全锁屏或界面显示在锁之上

总结

最后关于锁屏再总结一下:

ui层级图


UI时序图

1、锁屏分两类:非安全锁屏(如滑动锁屏)和安全锁屏(滑动锁屏)

2、他们都会加载到StatusBarWindowView上,而StatusBarWindowView在又会加载到window上从而显示出来

3、不同的是: 非安全锁屏在PanelHolder上,是StatusBarWindowView布局的一部分,所以随着开机加载systemui时就会加载上去,通过展开折叠等布局控制来显示与否 而安全锁屏是KeyguardHostView,它并不是StatusBarWindowView原有布局的一部分,而是根据上锁和解锁实际情况来动态加载和移除以及设置可见与不可见来显示与否,第一次加载是在完成开机动画触屏可显示时

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 162,408评论 4 371
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,690评论 2 307
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 112,036评论 0 255
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,726评论 0 221
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,123评论 3 296
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 41,037评论 1 225
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,178评论 2 318
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,964评论 0 213
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,703评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,863评论 2 254
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,333评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,658评论 3 263
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,374评论 3 244
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,195评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,988评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,167评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,970评论 2 279

推荐阅读更多精彩内容