AndroidL分析之Keyguard
AndroidL 鎖屏與SystemUI
AndroidL出來都這么久,AndroidM現在都有了,現在出來寫這個是有點晚了,這里僅是當作自己的一個總結吧,希望新接觸系統開發的人看到,能對他們有一點幫助。
在AndroidL之后(看了下M代碼,基本還是跟L一樣,沒變化),谷歌把之前相對獨立的Keyguard整合進了SystemUI之中,打開SystemUI目錄可以看到很多Keyguard命名的文件。這應該是為了可以復用SystemUI通知部分代碼,使系統通知可以在鎖屏上顯示。
但是這么一來,鎖屏與SystemUI界面代碼耦合,想要為系統鎖屏單獨增加個動畫特效都變得異常艱難,對SystemUI的調整也要同時考慮到會不會對鎖屏有影響。
這里先分析一下鎖屏代碼,以后再記錄下怎么反Google,怎么樣可以把系統鎖屏獨立出來的一些想法。由于AndroidKK鎖屏流程分析,網上資源比較豐富,為節省篇幅,更多的是討論AndroidL中鎖屏與KK不太一樣的地方。
鎖屏啟動過程
我們按照AndroidKK的思路,鎖屏應該有一個service通過AIDL與系統進行交互,觀察一下SystemUI中的代碼結構,發現了KeyguardService.java。其實keyguardService是在PhoneWindowManager的systemBooted()中啟動的:
/** {@inheritDoc} */@Overridepublic void systemBooted() {if (mKeyguardDelegate != null) {mKeyguardDelegate.bindService(mContext);//通過mKeyguardDelegate以bind方式啟動/連接鎖屏服務。mKeyguardDelegate.onBootCompleted();}synchronized (mLock) {mSystemBooted = true;}wakingUp();screenTurningOn(null);}KeyguardService.java的onCreate函數如下:
@Overridepublic void onCreate() {((SystemUIApplication) getApplication()).startServicesIfNeeded();mKeyguardViewMediator =((SystemUIApplication) getApplication()).getComponent(KeyguardViewMediator.class);}startServicesIfNeeded定義在SystemUIApplication中,是SystemUI用來初始化各個模塊的入口。
再看下KeyguardServiceonBind函數返回的binder對象:
private final IKeyguardService.Stub mBinder = new IKeyguardService.Stub() {private boolean mIsOccluded;@Overridepublic boolean isShowing() {return mKeyguardViewMediator.isShowing();}@Overridepublic boolean isSecure() {return mKeyguardViewMediator.isSecure();}@Overridepublic boolean isShowingAndNotOccluded() {return mKeyguardViewMediator.isShowingAndNotOccluded();}... ... }鎖屏這樣就跟系統服務PhoneWindowManager綁定了,系統可以控制鎖屏的顯示,在來電時或者其他應用窗口請求暫時隱藏鎖屏時,可以進行響應。
KeyguardService只是為系統提供一個查詢和控制鎖屏狀態的入口。那么鎖屏界面到底是如何加載顯示到屏幕上的呢?
鎖屏界面的加載顯示
我們再倒回去看一下,startServicesIfNeeded到底初始化了哪些模塊。
/** * Makes sure that all the SystemUI services are running. If they are already running, this is a * no-op. This is needed to conditinally start all the services, as we only need to have it in * the main process. * * <p>This method must only be called from the main thread.</p> */public void startServicesIfNeeded() {if (mServicesStarted) {return;}//省略判斷開機狀態代碼Log.v(TAG, "Starting SystemUI services.");final int N = SERVICES.length;for (int i=0; i<N; i++) {Class<?> cl = SERVICES[i];//各個模塊Classif (DEBUG) Log.d(TAG, "loading: " + cl);try {mServices[i] = (SystemUI)cl.newInstance();//實例化} catch (IllegalAccessException ex) {throw new RuntimeException(ex);} catch (InstantiationException ex) {throw new RuntimeException(ex);}mServices[i].mContext = this;//統一設置mContextmServices[i].mComponents = mComponents;//統一設置mComponentsif (DEBUG) Log.d(TAG, "running: " + mServices[i]);mServices[i].start();//調用每個模塊的start方法。if (mBootCompleted) {mServices[i].onBootCompleted();}}mServicesStarted = true;} /** * The classes of the stuff to start. */private final Class<?>[] SERVICES = new Class[] {com.android.systemui.keyguard.KeyguardViewMediator.class,com.android.systemui.recent.Recents.class,com.android.systemui.volume.VolumeUI.class,com.android.systemui.statusbar.SystemBars.class,com.android.systemui.usb.StorageNotification.class,com.android.systemui.power.PowerUI.class,com.android.systemui.media.RingtonePlayer.class};//所有的這些類都繼承自`SystemUI`這個父類。Google的這個做法非常好的把每個模塊分開初始化,又統一設置了同樣的Context和Components。這個應該算是哪種設計模式呢???我們找到了KeyguardViewMediator這個重要的類,它現在被放到了
SystemUI\src\com\android\systemui\keyguard\
中。職責跟KK時代相比基本沒變,負責管理鎖屏界面的加載,控制密碼鎖、pin碼鎖等界面的顯示。
KeyguardViewMediator的start方法很簡單:
@Overridepublic void start() {setup();//這個方法負責初始化變量和生成實例,AndroidKK是放到KeyguardViewMediator的onCreate中調用的。putComponent(KeyguardViewMediator.class, this);//由于在startServicesIfNeeded中統一設置了統一的`mComponents`,所以當其他模塊需要用到KeyguardViewMediator的時候,只需要簡單的調用`getComponent`方法就可以取到同一個對象,這個設計真是·簡單好用·。}setUp()初始化AlarmManager、PowerManager等并加載了鎖屏音,進行了一系列跟鎖屏相關的初始化工作。
繼續分析KeyguardViewMediator代碼handleShow:
/** * Handle message sent by {@link #showLocked}. * @see #SHOW */private void handleShow(Bundle options) {... ...mStatusBarKeyguardViewManager.show(options);//忽略判斷系統狀態和其他的代碼,關注這句,這個是跟布局顯示相關的調用。... ...}繼續向下追蹤代碼到了StatusBarKeyguardViewManager中的reset函數:
/** * Reset the state of the view. */public void reset() {if (mShowing) {if (mOccluded) {//occluded 變量判斷當前鎖屏是否需要被隱藏。(當前臺Window有SHOW_WHEN_LOCKED屬性的時候)mPhoneStatusBar.hideKeyguard();mBouncer.hide(false /* destroyView */);} else {showBouncerOrKeyguard();//這一句。}updateStates();}}往下看:
/** * Shows the notification keyguard or the bouncer depending on * {@link KeyguardBouncer#needsFullscreenBouncer()}. */private void showBouncerOrKeyguard() {if (mBouncer.needsFullscreenBouncer()) {//當需要顯示手機卡sim pin碼鎖屏的時候,返回true。// The keyguard might be showing (already). So we need to hide it.mPhoneStatusBar.hideKeyguard();mBouncer.show();//顯示安全鎖屏} else {mPhoneStatusBar.showKeyguard();//顯示傳統意義上的鎖屏。mBouncer.hide(false /* destroyView */);//hide了什么?mBouncer.prepare();}}看到這里,我們可能會有疑惑:這個hideKeyguardhide的是哪個keyguard?這個mBouncer又是個什么?也是鎖屏嗎?難道有兩個鎖屏在互相切換嗎?
前面已經講過,在AndroidL之后的代碼中,鎖屏布局的加載顯示已經移到了SystemUI模塊中。SystemUI這里的Keyguard指的是:
而Bouncer是加載安全鎖屏的容器:
找到了PhoneStatusBar和Bouncer的調用以后,我們查看他們的布局文件,可以發現,鎖屏是依附于SystemUI的布局文件進行加載的。我們看到的系統鎖屏,?其實是把SystemUI拉下展開之后的一個特殊狀態,在它上面可以很方便的顯示系統通知 。這個是Google在AndroidL之后重新設計的。
這樣可以方便的顯示系統通知,但是鎖屏View和SystemUI綁定到一起,如果要調整鎖屏的布局和動畫特效,就要小心可能會對SystemUI產生的影響,如果要更改鎖屏的觸摸操作、交互邏輯,很難不影響SystemUI。
我們看到華為榮耀的鎖屏效果,解鎖效果非??犰?#xff0c;UI元素和交互方式也比原生鎖屏豐富,他們肯定是把鎖屏獨立出來了。
原文地址:http://www.codingpuppy.com/post/androidl/m-suo-ping-fen-xi
總結
以上是生活随笔為你收集整理的AndroidL分析之Keyguard的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android7.0 PowerMana
- 下一篇: 先读懂CapsNet架构然后用Tenso