轉(zhuǎn)載自: http://blog.csdn.net/ahence/article/details/25400911 這兩天在搞一個鎖屏的小玩意兒,由于時間比較緊,先著重于功能實現(xiàn),未能從源代碼上分析,以下是一些個人的認(rèn)識與總結(jié),不足或錯誤之處,還請各位看官批評指正。 1.鎖屏頁的本質(zhì): 鎖屏界面其實也是一個Activity,只不過在該Activity上,屏蔽了Home鍵及Back鍵的響應(yīng),只有當(dāng)用戶解鎖的時候才可以進(jìn)入下一個界面,一般是Launcher界面。當(dāng)然用戶解鎖的方式可以是滑動解鎖,可以是密碼解鎖,完全在于自己對該鎖屏界面的設(shè)計,同樣可以像市場上很多鎖屏軟件一樣,可以加入一些有用的小玩意兒,比如天氣預(yù)報、時鐘、新聞等,因為這就是一個Activity,就像平時我們設(shè)計界面內(nèi)容一樣,理論上可以隨意設(shè)計,當(dāng)然也要符合鎖屏頁的原則,盡量簡潔美觀易用。 2.實現(xiàn)原理 理論上有兩種實現(xiàn)方式,一種是定制源代碼;另一種就是在應(yīng)用層開發(fā)一個鎖屏程序。除非特別需要,一般我們都是自己開發(fā)一個鎖屏程序。 如果自己開發(fā)一個鎖屏程序,一般是這樣做的: (1)系統(tǒng)在按下電源鍵關(guān)閉屏幕或點亮屏幕時會發(fā)出相應(yīng)的廣播,如Intent.ACTION_SCREEN_OFF和Intent.ACTION_SCREEN_ON,所以我們就可以注冊一個BroadcastReceiver來接收這些廣播,應(yīng)當(dāng)注意這些廣播都是受保護(hù)的,是由系統(tǒng)負(fù)責(zé)發(fā)送的。 (2)當(dāng)接收到這些廣播消息,我們就可以啟動鎖屏頁Activity,這樣就顯示出鎖屏界面效果了。 (3)在鎖屏頁上進(jìn)行解鎖,然后finish掉該鎖屏界面,實現(xiàn)解鎖效果。這里的要點和難點是屏蔽掉Home鍵和Back鍵,下面技術(shù)要點里會講。 3.技術(shù)要點 (1)屏蔽Back鍵 Back鍵比較容易屏蔽掉,重寫onKeyDown或onBackPressed方法即可,幾乎在所有Android版本上都是可以用的(并未親自測試所有版本,測了幾個版本并未遇到無效的情況)。 (2)屏蔽Home鍵 再來說屏蔽Home鍵,這個算是一個難點了。其實可以試想一下,如果運行了一個APP,當(dāng)Back鍵和Home鍵被屏蔽掉,那么這個程序是無法退出的,如果再是一個流氓軟件,這是多么惡心的用戶體驗??!除非你是一個很正規(guī)的鎖屏軟件,否則不建議屏蔽掉Home鍵。 Android4.0版本之前還是可以找到方法屏蔽Home鍵的,但是4.0之后則不再允許屏蔽Home鍵了,或許Google也是從安全性和用戶體驗的角度考慮,Home鍵的響應(yīng)直接在FrameWork層就處理了,而不會再傳到application層來處理。當(dāng)然網(wǎng)上也看到有方法偵聽到Home鍵,但是監(jiān)聽歸監(jiān)聽,但你無法屏蔽它。也就是說4.0之后,當(dāng)按下Home鍵時,系統(tǒng)默認(rèn)會響應(yīng)啟動Home頁,也就是Launcher桌面,我們在應(yīng)用層沒有辦法再屏蔽它。當(dāng)然你可以修改FrameWork層代碼,重新定制,這屬于第一種實現(xiàn)方式了,不在此文的探討范圍。 下面該是具體實現(xiàn)了: (2-1) Android 2.2-3.2版本(測試版本2.3.3) A.重寫以下兩個方法 @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(KeyEvent.KEYCODE_HOME==keyCode){ return true; } return super.onKeyDown(keyCode, event); } @Override public void onAttachedToWindow(){ this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD); super.onAttachedToWindow(); } B.加入對應(yīng)權(quán)限 <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> (2-2)Android4.0版本 在網(wǎng)上看到如下實現(xiàn)方法: A.public static final int FLAG_HOMEKEY_DISPATCHED = 0x80000000; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.getWindow().setFlags(FLAG_HOMEKEY_DISPATCHED, FLAG_HOMEKEY_DISPATCHED); setContentView(R.layout.main); } B.然后再重寫onKey事件。 經(jīng)測試,4.0.4版本可以,4.2.2無效,因此這種方式不能解決4.0+系統(tǒng)屏蔽Home鍵的根本問題。 鑒于上面所述,在Android4.0+,Application層已無法屏蔽Home鍵,因此只能另想它法。測試了百度鎖屏及Go鎖屏兩款鎖屏軟件,這兩款軟件都讓用戶進(jìn)行Home設(shè)置,避免點擊Home鍵取消鎖屏。所謂進(jìn)行Home設(shè)置,其實質(zhì)就是將該鎖屏軟件設(shè)置為默認(rèn)的桌面啟動頁,即Launcher啟動桌面,很明顯,因為無法屏蔽Home鍵,我們只能追隨它,點擊Home啟動Launcher,只不過是把Launcher設(shè)為我們自己的鎖屏App中的一個Activity而已了(其實這里是有技巧的,我開始也理解錯了,且看下文)。
把玩了一會兒百度鎖屏及Go鎖屏軟件,果斷把自己的鎖屏頁設(shè)為Home頁,設(shè)置方法如下: <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.HOME" /> <category android:name="android.intent.category.DEFAULT" /> 然后測試,把鎖屏頁設(shè)為默認(rèn)Launcher,這時候按下Home鍵果然就停在鎖屏頁了,因為此時點Home鍵本該啟動Home頁面,而此時我們的鎖屏頁就是Home頁。本以為這樣就可以了,但當(dāng)你解鎖后,在其他界面,比如短信界面按下Home鍵,我們希望回到某個桌面主頁(比如系統(tǒng)桌面主頁),但是此時卻會回到我們鎖屏頁,因為前面我們把鎖屏頁設(shè)置為默認(rèn)桌面主頁了,而百度鎖屏和Go鎖屏在點擊短信界面的Home時卻不會回到鎖屏頁,而是回到系統(tǒng)主頁(這里是可以在百度鎖屏里設(shè)置的,如果有多個桌面啟動Launcher,可以選擇)。 于是猜測可能是鎖屏?xí)r把鎖屏頁設(shè)為桌面主頁,解鎖后重新設(shè)置了一個桌面主頁,于是用百度鎖屏解鎖后,在應(yīng)用程序查看,桌面主頁依然是鎖屏程序而不是在設(shè)置里選擇的那個桌面啟動Launcher。開始有點困惑了,沒想通,果斷把百度鎖屏apk Dec一把,打開其配置文件一看,頓時恍然,也瞬間明白了進(jìn)行Home鍵設(shè)置時為什么要選擇一個解鎖后的桌面啟動頁。 在百度鎖屏里,原來鎖屏頁與設(shè)置為桌面啟動頁的是不同的兩個Activity,為了行文方便,姑且記鎖屏頁為A,記桌面啟動頁為B。鎖屏應(yīng)用啟動后,進(jìn)行Home設(shè)置,實質(zhì)是將B設(shè)置為默認(rèn)桌面啟動頁,這里注意的是B的theme是Theme.NoDisplay。關(guān)閉屏幕再開啟,百度鎖屏啟動了,點擊Home,實質(zhì)上是啟動了B,而B是不可見的,因此不會影響下面的A的操作,然后解鎖,顯示系統(tǒng)桌面(我在設(shè)置里選擇了系統(tǒng)桌面),如果再到短信界面按下Home鍵,其實是啟動了B,只是看起來沒有反應(yīng)而已,也不會影響操作,也就不會回到鎖屏頁了,因為鎖屏頁A不是桌面頁。只有在ScreenOn或ScreenOff時才會啟動鎖屏。 再來說前邊為什么要我們選擇一個解鎖后的桌面頁,是因為百度鎖屏解鎖后,會跳到該桌面頁,當(dāng)然我們可以直接使用系統(tǒng)桌面,不用在配置里選擇,這樣解鎖后就跳到系統(tǒng)桌面了。 究其原因,因為自己的小程序只有一個鎖屏Activity,就想當(dāng)然把它設(shè)為桌面啟動頁,因此不能實現(xiàn)百度鎖屏的效果;最后自己也另加一個Activity,不過我是使用了一個透明的Activity,并在啟動后把它移到后臺;在解鎖后,默認(rèn)啟動系統(tǒng)桌面,這樣就可以完美實現(xiàn)類似百度鎖屏的禁用Home鍵的效果了。原理搞清楚了,實現(xiàn)方法就殊途同歸了。 先總結(jié)到這里,Github源碼地址:Android_LockScreen。 |
|