春節前最後幾天瞭,工作上幾乎沒有什麼要做。大致整理下之前工作中寫的文檔,PPT,手冊. 由於去年一年完全轉到Android4.0+平臺上,Android2.3平臺已經不再做什麼項目,利用這幾天先把Android2.3平臺相關的文檔整理下,算是對android平臺一個總結。盡量都發佈到這裡,供大傢參加吧。這些文檔寫的時候有參照網絡上的,有的是從源代碼裡整理出來的,不過每一部分也都是通過分析源代碼,一步步分析驗證過的。
Android鎖屏機制原理分析
本文主要內容:
1、分析鎖屏界面的組成
2、源碼定制鎖屏主要工作
3、鎖屏佈局界面分析
4、鎖屏界面實現
本文分析版本具體是Android2.3版本
文件路徑主要有三個部分:
鎖屏框架: frameworks\base\policy\src\com\android\internal\policy\impl\
自定義View:frameworks\base\core\java\com\android\internal\widget\
資源:frameworks\base\core\res\
一、鎖屏界面的組成
1.1概述
通常 Android手機上大傢常見的界面隻有一種,成功後即可解鎖進入界面瞭。其實在Android手機中,正常的鎖屏界面由兩種不同性質的界面組成:
鎖屏界面是LockScreen;
解鎖界面是UnLockScreen,包括:
SIM卡解鎖SimUnlockScreen
圖案解鎖PatternUnlockScreen
密碼解鎖PasswordUnlockScreen
帳號解鎖AccountUnlockScreen
1.2 LockScreen界面
第一種界面稱之為LockScreen界面(為瞭敘述方便,我們稱為“鎖屏界面),即我們通常所見到的界面,手機廠商一般定制該界面。界面如下所示:
該界面對應自定義View的是LockScreen.java類路徑位於:
frameworks\base\policy\src\com\android\internal\policy\impl\LockScreen.java
1.3 UnLockScreen界面
第二種界面稱之為UnLockScreen界面(為瞭後文敘述方便,我們姑且稱為“解鎖界面”),一般由Android源碼提供,有如下四種:
①、圖案開鎖界面 —- PatternUnlockScreen.java類(自定義LinearLayout)
路徑位於:frameworks\policies\base\phone\com\android\internal\policy\impl\PatternUnlockScreen.java
界面顯示為:
②、PIN開鎖界面 —- SimUnlockScreen.java 類 (自定義LinearLayout)
界面顯示為:(圖片省略)
③、密碼開鎖界面 —- PasswordUnlockScreen.java類 (自定義LinearLayout)
路徑位於:frameworks\base\policy\src\com\android\internal\policy\impl\PasswordUnlockScreen.java
④、GoogleAccount 開鎖界面 ,即Google賬戶開鎖界面。一般用於當用戶輸入密碼錯誤次數超過上限值時,系統會提示你輸入Google賬戶去開鎖。註意:開啟它需要你手動設置賬戶與同步,否則該界面是不會出來的。對應的源文件是: AccountUnlockScreen.java類(自定義LinearLayout)
路徑位於:frameworks\policies\base\phone\com\android\internal\policy\impl\AccountUnlockScreen.java
界面顯示為:
1.4 顯示規則
可以按照如下辦法選擇開啟哪一種開鎖界面:設置—>位置和安全—>設置屏幕鎖定,具體選擇那種開鎖界面。
這兩種界面的組合也是有很多變化的,總的規則如下:首先顯示LockScreen界面,接著判斷是否開啟瞭UnLockScreen界面,如果設置瞭UnLockScreen界面,則進入對應的UnLockScreen界面去解鎖,才算成功解鎖。但存在一種特殊的情況,就是假如我們選擇瞭圖案UnLockScreen界面,是不會顯示LockScreen界面,而隻會顯示UnLockScreen界面。
二、定制主要工作
一般自定義鎖屏主要也是修改默認的鎖屏LockScreen.java,故主要介紹一下默認的鎖屏。
源碼定制鎖屏我們需要修改的主要文件包括:
1. 鎖屏主頁面
frameworks\policies\base\phone\com\android\internal\policy\impl\LockScreen.java
2. 滑動開鎖控件
frameworks\base\core\java\com\android\internal\widget\SlidingTab.java
3. 時間顯示
frameworks\base\core\java\com\android\internal\widget\DigitalClock.java
4. 豎屏佈局文件
frameworks\base\core\res\res\layout\keyguard_screen_tab_unlock.xml
5. 橫屏佈局文件
frameworks\base\core\res\res\layout\keyguard_screen_tab_unlock_land.xml
三、鎖屏界面佈局分析
接下來分析整個界面的佈局。鎖屏界面(豎屏)如下圖:
分析文件(以豎屏為例):frameworks\base\core\res\res\layout\keyguard_screen_tab_unlock.xml
3.1 佈局Xml代碼
上面是android2.3源代碼。
3.2 控件說明
@+id/carrier:顯示運營商信息,沒有插入SIM卡時顯示“沒有SIM卡”,沒有信號時會顯示“(無服務)”
@+id/emergencyCallText:固定字符串。“隻能使用緊急呼叫”,在沒有插入SIM卡時顯示。
@+id/time:顯示時間信息,包括12和24小時制。這裡是單獨寫瞭一個ViewGroup,後面會專門介紹。
@+id/date:顯示日期信息,包括星期。如果需要修改格式,請在對應語言的donottranslate-cldr.xml文件中找到需要的格式
@+id/status1、@+id/status2:分別顯示充電、鬧鐘信息。
@+id/tab_selector:滑動解鎖
@+id/emergencyCallButton:緊急撥號按鈕。當沒有插入SIM卡時顯示。
這裡可以對佈局進行任意修改,但建議不要修改ID名稱,因為上面所顯示的都是常用的信息,一般手機都會包括這些。如果確實要刪除,請先確定別的類中是否有包含這些控件。比如打電話和接電話界面。
註意問題:這裡如果刪除或者新增控件,需要全部編譯,不能隻編譯framework層代碼。具體什麼原因暫時未找到。
四、鎖屏界面的實現
4.1 主要層次
任何一種界面都是由各種View/ViewGroup(當然包括自定義的)組成的,然後根據系統對應的狀態值的改變去更新這些View的顯示狀態,鎖屏界面自然也是如此。鎖屏界面的實現最頂層是采用瞭FrameLayout去控制的,當然內部也嵌套瞭很多層,內嵌層數的增多的一點好處就是我們可以分開而治,具體針對每層去做相應的更新。難處就是看代碼看的很鬱悶。
當界面復雜時,可以借用工具—Hierarchy Viewer ,通過它,我們很清晰的弄明白整個View樹的繼承層次,一個佈局結構,當然,看源代碼也是必須的。
整個鎖屏界面的繼承層次如下(部分以及設置瞭圖案開鎖界面),更加完整的圖大傢可以使用Hierarchy Viewer 工具查看。
上圖中比較重要的幾個視圖說明如下:
LockPatternKeyguardView 繼承自FrameLayout :作為LockScreen和UnLockScreen的載體,用來控制顯示LockScreen還是UnLockScreen界面。
LockScreen 繼承自FrameLayout
PatterUnlockScreen ViewGroup類型 : 圖案解鎖界面
KeyguardViewHost 繼承自FrameLayout, 該ViewGroup作為頂層View,作為WindowManager的裝飾對象添加至窗口。
它和LockPatternKeyguardView關系相當於DecorView和我們Activity內設置的資源佈局一樣。
4.2 兩個廣播
為瞭在亮屏時,達到取消顯示界面的效果,我們還需要知道 一下兩個廣播:
屏幕變暗以及屏幕點亮的廣播
android.intent.action.SCREEN_ON —– 屏幕變亮
android.intent.action.SCREEN_OFF —– 屏幕點暗
4.3大致流程
4.3重要相關文件分析
1、KeyguardScreen 類接口
功能:該接口的主要功能是為每個需要顯示的界面LockScreen或者UnLockScreen定義瞭四個方法,使其在不同的狀態能夠得到相應處理。
路徑:\frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardScreen.java
其源代碼釋義如下:
/** * Common interface of each {@link android.view.View} that is a screen of * {@link LockPatternKeyguardView}. */ public interface KeyguardScreen { /** Return true if your view needs input, so should allow the soft * keyboard to be displayed. */ boolean needsInput(); //View是否需要輸入數值,即該界面需要鍵盤輸入數值 /** This screen is no longer in front of the user.*/ void onPause();//當該界面不處於前臺界面時調用,包括處於GONE或者該界面即將被remove掉 /** This screen is going to be in front of the user. */ void onResume();//相對於onPause()方法,當該界面不處於前臺界面時調用,處於VISIBLE狀態時調用 /** This view is going away; a hook to do cleanup. */ void cleanUp();//該界面即將被remove掉 ,即不在需要 }
2、KeyguardScreenCallback類接口
功能:每個需要顯示的界面:LockScreen或者UnLockScreen都保存瞭該對象的唯一實例,用來向控制界面匯報情況。
路徑:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardScreenCallback.java
其源代碼釋義如下:
/** Within a keyguard, there may be several screens that need a callback * to the host keyguard view. */ public interface KeyguardScreenCallback extends KeyguardViewCallback { /** Transition to the lock screen*/ void goToLockScreen(); //當前界面跳轉為LockScreen ,而不是UnLockScreen /** Transition to the unlock screen.*/ void goToUnlockScreen();//LockScreen成功開鎖 ,是否需要顯示UnLockScreen,否則,直接開鎖成功。 //忘記瞭開鎖圖案,即我們需要跳轉到Google 賬戶去開鎖。 void forgotPattern(boolean isForgotten); boolean isSecure();//當前機器是否安全,例如:設置瞭圖案、密碼開鎖等 boolean isVerifyUnlockOnly(); /**Stay on me, but recreate me (so I can use a different layout).*/ void recreateMe(Configuration config); //重新根據手機當前狀態,顯示對應的Screen. /** Take action to send an emergency call. */ void takeEmergencyCallAction(); //緊急呼叫時的處理行為. /** Report that the user had a failed attempt to unlock with password or pattern.*/ void reportFailedUnlockAttempt(); //在UnLockScreen界面登陸失敗時處理 /** Report that the user successfully entered their password or pattern.*/ void reportSuccessfulUnlockAttempt();//在UnLockScreen界面登陸成功時處理 /** Report whether we there's another way to unlock the device. * @return true */ boolean doesFallbackUnlockScreenExist(); }
3、KeyguardViewCallback類 接口
功能: 提供瞭一些接口用來接受用戶操作Screen的結果。
路徑:frameworks\base\policy\src\com\android\internal\policy\impl\KeyguardViewCallback.java
其源代碼釋義如下:
/** * The callback used by the keyguard view to tell the {@link KeyguardViewMediator} * various things. */ public interface KeyguardViewCallback { /** Request the wakelock to be poked for the default amount of time. */ void pokeWakelock(); //保存屏幕在一定時間內處於亮屏狀況 , 默認時間為5s或者10s /** Request the wakelock to be poked for a specific amount of time. */ void pokeWakelock(int millis);//根據給定時間值,使屏幕在該事件段內保持亮屏狀況 /** Report that the keyguard is done. * @param authenticated Whether the user securely got past the keyguard. * the only reason for this to be false is if the keyguard was instructed * to appear temporarily to verify the user is supposed to get past the * keyguard, and the user fails to do so. */ //成功的完成開鎖,可以進入手機界面瞭。參數為ture表示是否正大光明的開鎖,例如:圖案正確,密碼輸入正確。 void keyguardDone(boolean authenticated); /**Report that the keyguard is done drawing. */ void keyguardDoneDrawing(); //整個鎖屏界面draw()過程繪制完成時,回調該方法. }
說明:
Android平臺鎖屏機制相差並不是很大,高版本平臺的鎖屏機制都會處於各種原因對之前版本的鎖屏模塊進行改進和完善,但是隻要分析明白其中一個版本的鎖屏原理和流程,那麼對於其他版本的鎖屏模塊都會很快搞明白。