Android6.0 systemui锁屏流程解析
来源:互联网 发布:开机mysql弹出怎么办 编辑:程序博客网 时间:2024/05/29 08:08
systemui的启动流程
谈到锁屏我们先来简单看下systemui的启动流程
SystemUI常驻于系统,通过Service实现,关键Service:SystemUIService是在SystemServer.java中被启动的。
Android的启动分为内核启动、Android启动、launcher启动,我们的SystemServer就处于Android启动中,systemui的启动以下是大致流程: init->ServiceManager->Zygote->SystemServer->SystemUIService-->SystemUIApplication-->SystemUI.start(KeyguardViewMediator,Recents等SystemUI 子类开始各司其职的正常工作起来)
systemui具体的启动流程代码可以参考博客,这里不再熬述:Android5.1SystemUI详解 https://wenku.baidu.com/view/8338b1b9cf84b9d529ea7a17.html
涉及的代码
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
锁屏分类
那么锁屏界面是怎样加载到window显示出来的呢?首先需要明确是的6.0分两类锁屏(非安全锁屏(滑动锁屏)和安全锁屏(图案,pin等))
1、非安全锁屏,称之为notification keyguard,这个类型的keyguard已经和statusbar融为一体了,可以通过PhoneStatusBar.java的对象直接进行控制;
2、安全锁屏,比如密码、图案、PIM码、PUK码等锁屏方式的锁屏界面,通过KeyguardBouncer.java进行控制;锁屏加载流程
非安全锁屏加载流程
首先非安全锁屏界面,是NotificationPanelView的一部分,在systemui启动SystemUI.start就已经加载,看下systemui开机启动流程图
因为这里重点是锁屏,所以我们从PhoneStatusBar.start()开启看,前面的请看上面的链接
PhoneStatusBar.start会调用父类BaseStatusBar的start,继续调用PhoneStatusBar的createAndAddWindows(),然后继续调用addStatusBarWindow()来创建通知锁屏等StatusBarWindowView并加到window上
非安全锁屏是NotificationPanelView的一部分,而NotificationPanelView又是StatusBarWindowView的一部分,所以这样就已经将非安全锁屏加载好了,至于显示还是隐藏就只是NotificationPanelView界面调整的问题了,具体的view的层级和控制代码量太多,这里不做深入分析
private void addStatusBarWindow() { makeStatusBarView();//-----创建PhoneStatusBarView mStatusBarWindowManager = new StatusBarWindowManager(mContext); mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());//将PhoneStatusBarView添加到window }protected PhoneStatusBarView makeStatusBarView() { ...... mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_status_bar, null); ........}
安全锁屏加载流程
安全锁屏systemui启动时准备
上面还只是加载了非安全锁屏界面,那安全锁屏界面呢?实际上安全锁屏界面也会加载到StatusBarWindowView,只不过是动态加载和移除的,并不是直接放在布局里初始化加载,我们简单看下锁屏ui层级
在PhoneStatusBar.start()方法里加载完StatusBarWindowView后,还会调用startKeyguard()来完全安全锁屏的一些初始化准备工作,这里关注的是将StatusBarWindowView作为属性赋值给安全锁屏的操控类KeyguardBouncer
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()和systemBooted()方法开始分析。
systemReady()调用在systemBooted()之前,至于具体的调用流程这里不做分析,但大致也是从SystemServer.java中main函数会调用startOtherServices()方法跟下去:
那么现在看下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.android.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();控制的是非安全锁屏,而mBouncer.show(true)和mBouncer.hide(false)控制的是安全锁屏,也就是说非安全锁屏和安全锁屏在这里开始分别由PhoneStatusBar和KeyguardBouncer管理,前面说了非安全锁屏这里不做深入分析,下面重点看安全锁屏,安全锁屏界面KeyguardHostView作为KeyguardBouncer的属性直接被操控,而要不要先显示非安全锁屏是根据锁屏模式来的,由于锁屏情况太多现在假设是图案解锁,具体再往下来,根据目前场景来看是会走下面abcdef
/** * 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是安全锁屏主界面,实现了SecurityCallback接口,其他地方用到的SecurityCallback其实就是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添加到父布局KeyguardSecurityViewFlipper从而到KeyguardSecurityContainer上 updateSecurityView(v); view = (KeyguardSecurityView)v; } return view; }}
到目前位置通过mSecurityViewFlipper.addView(v);最终将安全view添加到StatusBarWindowView,但是安全锁屏跟布局还是不可见的,所有代码走到KeyguardBouncer的e处,那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的f处,也就是把安全锁屏根布局设置为可见mRoot.setVisibility(View.VISIBLE);
ok,终于大功告成,锁屏控件都已加载到StatusBarWindowView上且可见。
锁屏调用入口
其他的场景,如解锁,灭屏等按照上面的思路结构都很容易分析不再熬述,调用入口目前总结如下几种情况:
1、KeyguardSecurityCallback.dismiss(true)-->KeyguardSecurityContainer.SecurityCallback.dismiss(true)-->实际对象就是KeyguardHostView.dismiss(true)-->......
这种一般是解锁了一种安全锁屏onClick里
2、ViewMediatorCallback-->实际对象就是KeyguardViewMediator.mViewMediatorCallback
这种一般是应用内直接调用,比如添加手机防盗解锁,受到上锁广播时直接调用showLocked(null)或resetStateLocked()
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原有布局的一部分,而是根据上锁和解锁实际情况来动态加载和移除以及设置可见与不可见来显示与否,第一次加载是在完成开机动画触屏可显示时
- Android6.0 systemui锁屏流程解析
- Android6.0 SystemUI中的Notification流程
- Android6.0 反编译systemUI
- Android6.0SystemUI状态栏更新
- android6.0 SystemUI之快捷设置区域QSPanel及点击事件流程分析
- android6.0 SystemUI之快捷设置区域QSPanel及点击事件流程分析
- android4.0 systemui启动流程
- Android6.0 keyguard锁屏加载流程分析
- Android6.0 keyguard锁屏加载流程分析
- android6.0锁屏界面接收新通知处理流程
- Android6.0 keyguard锁屏加载流程分析
- (原创)Android6.0亮屏流程分析
- Android6.0 Sensor流程
- Android6.0来电流程
- Android6.0 SystemUI启动简析及图标显示刷新
- Android6.0 SystemUI之网络信号栏显示刷新
- Android6.0 SystemUI之网络信号栏显示刷新
- Android6.0 SystemUI启动简析及图标显示刷新
- 桶排序(hash排序)
- for循环练习
- 【Android】Binder传送文件描述符分析
- 斯坦福机器学习课程笔记1
- aliyun阿里云Maven仓库地址——加速你的maven构建
- Android6.0 systemui锁屏流程解析
- 【LeetCode】567. Permutation in String
- Hadoop之HDFS(一)
- JSP隐式对象
- java数组查询
- python用不同颜色打印
- 在Python编程语言中使用os.path.isdir()函数操作介绍
- c语言基础
- 串口发送一帧数据时,两个字节的间隔时间是多少?