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

Android 6.0 SystemUI 鎖屏流程解析

談到鎖屏我們先來(lái)簡(jiǎn)單看下systemUI的啟動(dòng)流程

SystemUI常駐于系統(tǒng)链烈,通過(guò)Service實(shí)現(xiàn)能曾,關(guān)鍵service:SystemUIService是在SystemServer.java中啟動(dòng)笆环。

Android的啟動(dòng)分為內(nèi)核啟動(dòng)浦译,android啟動(dòng)战惊,Launcher啟動(dòng)信柿,我們的SystemServer就處于Android啟動(dòng)中钠绍,SystemUI的啟動(dòng)以下是大致流程:init->ServiceManager->Zygote->SystemServer->SystemUIService-->SystemUIApplication-->SystemUI.start(KeyguardViewMeditor,Recents等SytsemUI子類開始各司其職的正常工作起來(lái))

SystemUI具體的啟動(dòng)流程代碼可以參考博客舆声。

設(shè)計(jì)代碼

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顯示出來(lái)的呢?首先需要明確的是6.0分為兩類鎖屏(非安全鎖屏<滑動(dòng)鎖屏>和安全鎖屏<圖案和pin等>)

1.非安全鎖屏柳爽,稱之為notification keyguard媳握,這個(gè)類型的keyguard 已經(jīng)和statusbar融為一體,可以通過(guò)PhoneStatusBar.java對(duì)象直接進(jìn)行控制磷脯;

2.安全鎖屏蛾找,比如密碼,圖案赵誓,PIN碼打毛,PUK碼等鎖屏的鎖屏界面柿赊,通過(guò)keyguardBouncer.java進(jìn)行控制

鎖屏加載流程


非安全鎖屏加載流程

首先非安全鎖屏界面,是NotificationPanelView的一部分幻枉,在SystemUI啟動(dòng)SystemUI.start就已經(jīng)加載碰声,看下SystemUI開機(jī)啟動(dòng)流程圖

因?yàn)檫@里重點(diǎn)是鎖屏,所以我們從PhoneStatusBar.start()開啟看展辞。

PhoneStatusBar.start會(huì)調(diào)用父類BaseStatusBar的start(),繼續(xù)調(diào)用PhoneStatusBar的createAndAddWindow()奥邮,然后繼續(xù)調(diào)用addStatusBarWindow來(lái)創(chuàng)建通知鎖屏等StatusBarWindowView并加到window上。

非安全鎖屏是NotificationPanelView的一部分罗珍,而NotificationPanelView又是StatusBarWindowView的一部分洽腺,所以這樣就已經(jīng)將非安全模式加載好了,至于顯示還是隱藏就只是NotificationPanelView界面調(diào)整的問(wèn)題了覆旱,具體的View層級(jí)和控制代碼量太多蘸朋,暫不做深入分析

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

安全鎖屏加載流程

安全鎖屏SystemUI啟動(dòng)時(shí)準(zhǔn)備

上面還只是加載了非安全鎖屏界面,那安全鎖屏界面呢?實(shí)際上安全鎖屏界面也會(huì)加載到StatusBarWindowView扣唱,只不過(guò)是動(dòng)態(tài)加載和移除藕坯,并不是直接放在布局里初始化加載,我們簡(jiǎn)單看下鎖屏UI層級(jí)

在PhoneStatusBar.start()方法里加載完StatusBarWindowView后噪沙,還會(huì)調(diào)用startKeyGuard()來(lái)安全鎖屏的一些初始化準(zhǔn)備工作炼彪,這里關(guān)注的是將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;
??? }
}

安全鎖屏開機(jī)展示流程

時(shí)序圖

到現(xiàn)在為止還只是StatusBarWindowView與KeyguardBouncer關(guān)聯(lián),那安全鎖屏界面到底是什么時(shí)候加載到StatusBarWindowView從而顯示給我們呢正歼?實(shí)際上我們前面也說(shuō)了辐马,安全鎖屏界面其實(shí)是動(dòng)態(tài)的加載和移除的,從未上鎖到上鎖就會(huì)addView局义,完成全部解鎖就會(huì)removeView喜爷,比如開機(jī)完成后就會(huì)上鎖,下面我們來(lái)分析下開機(jī)展示安全鎖屏流程萄唇,首先看下時(shí)序圖:



代碼流程

開機(jī)啟動(dòng)流程其實(shí)也很復(fù)雜檩帐,但是本文重點(diǎn)在于KeyGuard鎖屏的展示,所以我們從開機(jī)啟動(dòng)調(diào)用到PhoneWindowManager的SystemReady()和SystemReady()和SystemBooted()方法開始分析另萤。

systemReady()調(diào)用systemBooted()之前湃密,至于具體的調(diào)用流程這里不做分析,大致也是SystemServer.java中main函數(shù)會(huì)調(diào)用startOtherService()方法跟下去:

那么現(xiàn)在看下去PhoneWindowManager的systemReady()和systemBooted()這兩個(gè)方法

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()時(shí)才能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();//-----前面調(diào)用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;
??????? }

??? };
?}

因?yàn)閏onfig_keyguardComponent就是com.android.systemui/com.andoid.systemui.keyguard.KeyguardService,所以IKeyguardService.Stub.asInterface(service)就是KeyguardService里的private final IKeyguardService.Stub mBinder俩由,也就是KeyguardServiceWrapper里的private IKeyguardService mService,所以接著調(diào)用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();
??????? }
??? }
}

終于走到我們鎖屏模塊最關(guān)鍵的調(diào)度類KeyguardViewMediator癌蚁,功能上負(fù)責(zé)處理keyguard試圖的事件幻梯,鎖屏事件的入口兜畸,下面繼續(xù)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);
??? }
???
}

通過(guò)代碼可知,最后將show動(dòng)作交給StatusBarkeyguardViewManager來(lái)處理碘梢,實(shí)際上這類直接鎖屏相關(guān)動(dòng)作最后都會(huì)交給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動(dòng)作都會(huì)調(diào)用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)控制的是安全鎖屏恩沛,也就是說(shuō)非安全鎖屏和安全鎖屏在這里開始分別由PhoneStatusBar和KeyguardBouncer管理在扰,前面說(shuō)了非安全鎖屏這里不做升入分析,下面重點(diǎn)看安全鎖屏雷客,安全鎖屏界面KeyguardHostView作為KeyguardBouncer的屬性直接被操控芒珠,而要不要先顯示非安全鎖屏是根據(jù)鎖屏模式來(lái)的,由于鎖屏情況太多現(xiàn)在假設(shè)是圖案解鎖搅裙,具體在往下來(lái)皱卓,根據(jù)目前場(chǎng)景來(lái)看是會(huì)走到

/**
?* 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) {//-----實(shí)際上顯示、重置部逮、移除動(dòng)作都會(huì)調(diào)用到
??????? ensureView();//----確保安全鎖屏界面有創(chuàng)建并添加到StatusBarWindowView上娜汁,并且安全界面初始化時(shí)是不可見的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是安全鎖屏界面,當(dāng)已是可見是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);//-----安全界面設(shè)置成可見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) {//-----安全界面跟布局,一般無(wú)鎖到有鎖初始化蜈漓,完全完成解鎖時(shí)置空
??????????? 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是安全鎖屏主界面,實(shí)現(xiàn)了SecrityCallBack接口宫盔,其他地方用到的SeurityCakkback其實(shí)就是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的容,會(huì)具體根據(jù)安全模式展示不同的View灼芭,繼續(xù)往下面

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;
??? }

}

到目前位置通過(guò)mSercutityViewFliper.addView(v);最終將安全view添加到StatusBarWindowView有额,但是安全鎖屏跟布局還是不可見的,所以代碼走到KeyguardBouncer的處彼绷,那么mKeyguardView.dismiss()又做了什么呢巍佑,繼續(xù)往下跟

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寄悯,當(dāng)前場(chǎng)景下參數(shù)未false萤衰,繼續(xù)往下看:

/**
???? * 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
???? */
??? //-----顯示下一個(gè)安全鎖屏界面,參數(shù)很重要猜旬,參數(shù)表示是否經(jīng)過(guò)驗(yàn)證
??? boolean showNextSecurityScreenOrFinish(boolean authenticated) {
??????? if (DEBUG) Log.d(TAG, "showNextSecurityScreenOrFinish(" + authenticated + ")");
??????? boolean finish = false;
??????? if (mUpdateMonitor.getUserCanSkipBouncer(
??????????????? KeyguardUpdateMonitor.getCurrentUser())) {
??????????? //-----可以跳過(guò)安全鎖屏脆栋,直接完全所有鎖屏
??????????? finish = true;
??????? } else if (SecurityMode.None == mCurrentSecuritySelection) {
??????????? //當(dāng)前是非安全鎖屏(滑動(dòng))倦卖,獲取下一個(gè)鎖屏模式,如果還是非安全鎖屏(滑動(dòng)),直接完全所有鎖屏,否則顯示下一個(gè)安全鎖屏界面
??????????? 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) {
??????????? //-----如果是經(jīng)過(guò)驗(yàn)證的椿争,當(dāng)前的是普通的安全模式怕膛,那么完成全部解鎖,如果是pin\puk之類的第三類動(dòng)態(tài)的就繼續(xù)檢查下一個(gè)鎖屏秦踪,
??????????? //-----下一個(gè)是安全鎖屏就繼續(xù)顯示下一個(gè)安全鎖屏界面褐捻,否則完成全部解鎖
??????????? 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;
??? }

當(dāng)前場(chǎng)景下都不滿足柠逞,直接返回false,那么代碼繼續(xù)走到KeyguardBouncer的處希坚,也就是把安全鎖屏根布局設(shè)置為可見mRoot.setVisibility(View.VISIBLE);最終鎖屏控件都已加載到StatusBarWindowView上且可見

鎖屏調(diào)用入口

其他場(chǎng)景边苹,如解鎖,滅屏等按照上面的思路結(jié)構(gòu)都很容易分析就不再贅述裁僧,調(diào)用入口目前如下幾種情況个束;

1KeyguardSecurityCallBack.dismiss(true)-->KeyguardSecurityContainer.SecurityCallback.dismiss(true)-->實(shí)際上對(duì)象就是KeyguardHostView.dismiss(true)-->......這中一般是解鎖了安全鎖屏onClick里

2ViewMeditorCallback-->實(shí)際對(duì)象就是KeyguardViewMeditor.mViewMeditorCallback

這種一般是應(yīng)用內(nèi)直接調(diào)用,比如添加手機(jī)防盜解鎖聊疲,受到上鎖廣播時(shí)直接調(diào)用showLocked(null)或resetStatLocked()


3茬底、KeyguardServiceDelegate-->綁定KeyguardService? ?????

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

signature:這種權(quán)限級(jí)別,只有當(dāng)發(fā)請(qǐng)求的應(yīng)用和接收此請(qǐng)求的應(yīng)用使用同一簽名文件获洲,并且聲明了該權(quán)限才會(huì)授權(quán)阱表,并且是默認(rèn)授權(quán),不會(huì)提示用戶授權(quán)? ???? 這種一般是frameworks通過(guò)binder服務(wù)調(diào)用贡珊,如開機(jī)上鎖最爬,滅屏上鎖等?

4、通過(guò)屬性android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUAR ????????????????????? android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKE ???

第三方應(yīng)用一般因?yàn)闄?quán)限問(wèn)題通過(guò)屬性來(lái)控制消除非安全鎖屏或界面顯示在鎖之上

總結(jié)

最后關(guān)于鎖屏再總結(jié)一下:

ui層級(jí)圖


UI時(shí)序圖

1门岔、鎖屏分兩類:非安全鎖屏(如滑動(dòng)鎖屏)和安全鎖屏(滑動(dòng)鎖屏)

2爱致、他們都會(huì)加載到StatusBarWindowView上,而StatusBarWindowView在又會(huì)加載到window上從而顯示出來(lái)

3寒随、不同的是: 非安全鎖屏在PanelHolder上糠悯,是StatusBarWindowView布局的一部分,所以隨著開機(jī)加載systemui時(shí)就會(huì)加載上去妻往,通過(guò)展開折疊等布局控制來(lái)顯示與否 而安全鎖屏是KeyguardHostView互艾,它并不是StatusBarWindowView原有布局的一部分,而是根據(jù)上鎖和解鎖實(shí)際情況來(lái)動(dòng)態(tài)加載和移除以及設(shè)置可見與不可見來(lái)顯示與否讯泣,第一次加載是在完成開機(jī)動(dòng)畫觸屏可顯示時(shí)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纫普,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子好渠,更是在濱河造成了極大的恐慌局嘁,老刑警劉巖溉箕,帶你破解...
    沈念sama閱讀 216,402評(píng)論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異悦昵,居然都是意外死亡肴茄,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門但指,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)寡痰,“玉大人,你說(shuō)我怎么就攤上這事棋凳±棺梗” “怎么了?”我有些...
    開封第一講書人閱讀 162,483評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵剩岳,是天一觀的道長(zhǎng)贞滨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拍棕,這世上最難降的妖魔是什么晓铆? 我笑而不...
    開封第一講書人閱讀 58,165評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮绰播,結(jié)果婚禮上骄噪,老公的妹妹穿的比我還像新娘。我一直安慰自己蠢箩,他們只是感情好链蕊,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著谬泌,像睡著了一般滔韵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上掌实,一...
    開封第一講書人閱讀 51,146評(píng)論 1 297
  • 那天陪蜻,我揣著相機(jī)與錄音,去河邊找鬼潮峦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛勇婴,可吹牛的內(nèi)容都是我干的忱嘹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼耕渴,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼拘悦!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起橱脸,我...
    開封第一講書人閱讀 38,896評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤础米,失蹤者是張志新(化名)和其女友劉穎分苇,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屁桑,經(jīng)...
    沈念sama閱讀 45,311評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡医寿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蘑斧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片靖秩。...
    茶點(diǎn)故事閱讀 39,696評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖竖瘾,靈堂內(nèi)的尸體忽然破棺而出沟突,到底是詐尸還是另有隱情,我是刑警寧澤捕传,帶...
    沈念sama閱讀 35,413評(píng)論 5 343
  • 正文 年R本政府宣布惠拭,位于F島的核電站,受9級(jí)特大地震影響庸论,放射性物質(zhì)發(fā)生泄漏职辅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評(píng)論 3 325
  • 文/蒙蒙 一葡公、第九天 我趴在偏房一處隱蔽的房頂上張望罐农。 院中可真熱鬧,春花似錦催什、人聲如沸涵亏。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)气筋。三九已至,卻和暖如春旋圆,著一層夾襖步出監(jiān)牢的瞬間宠默,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工灵巧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搀矫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,698評(píng)論 2 368
  • 正文 我出身青樓刻肄,卻偏偏與公主長(zhǎng)得像瓤球,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子敏弃,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,072評(píng)論 25 707
  • 隨性所欲閱讀 718評(píng)論 2 1
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法卦羡,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法绿饵,異常的語(yǔ)法欠肾,線程的語(yǔ)...
    子非魚_t_閱讀 31,622評(píng)論 18 399
  • 活動(dòng)已過(guò)這么多周了,僅僅剩下一周的時(shí)間拟赊。隊(duì)員們都疲了刺桃。下午回來(lái)我要給他們開周會(huì)。我醞釀了下要门,不能跟他們談業(yè)績(jī)談倒計(jì)...
    廬山春曉聞啼鳥閱讀 127評(píng)論 0 0
  • 一直以為沒有窗體邊框的程序是別的模式呢虏肾,原來(lái)不是,是設(shè)置屬性隱藏了欢搜。屬性:WindowStyle="None" ...
    冰點(diǎn)雨閱讀 4,694評(píng)論 0 0