相信在Android應用上,很多時候邏輯是需要屏蔽Home鍵的,但這個使用者體驗是否需要,就看各位的需求了。
一般的方法屏蔽Home鍵,大家一定看過不少文章了。我總結一下,先說一下一般情況下Activity的屏蔽按鍵和Home鍵吧。
屏蔽其他鍵,重寫onKeyDown
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
Log.i(TAG,"keycode="+keyCode + " isBan="+isBan);
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
Log.i(TAG,"KEYCODE_BACK");
return true;
}
return super.onKeyDown(keyCode, event);
}
大家會發現,這裡屏蔽Home鍵是捕捉不到的,因為大家的權限一般是User是以是無效的。
而其實android處理Home鍵等系統級按鍵是有一定的處理的。
引用
看看源碼是怎樣處理的 \frameworks\policies\base\phone\com\android\internal\policy\impl\PhoneWindowManager.java #1092
// First we always handle the home key here, so applications
// can never break it, although if keyguard is on, we do let
// it handle it, because that gives us the correct 5 second
// timeout.
if (code == KeyEvent.KEYCODE_HOME) {
// If a system window has focus, then it doesn't make sense
// right now to interact with applications.
WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;
if (attrs != null) {
final int type = attrs.type;
if (type == WindowManager.LayoutParams.TYPE_KEYGUARD
|| type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {
// the "app" is keyguard, so give it the key
return false;
}
final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;
for (int i=0; i<typeCount; i++) {
if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {
// don't do anything, but also don't pass it to the app
return true;
}
通過源碼,我們不難發現兩個的參數 WindowManager.LayoutParams.TYPE_KEYGUARD和
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
借鑒于此,重寫onAttachedToWindow,以實作屏蔽Home鍵
public void onAttachedToWindow() {
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
super.onAttachedToWindow();
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 華麗的分界線,以下内容更精彩- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
輪到dialog了,如果在Activity彈出dialog,在Activity設定以上2個方法是沒辦法屏蔽的。
其實,原理是一樣的,隻是地方不一樣而已。
final Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.mydailog);
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
dialog.show();
dialog.setOnKeyListener(new android.content.DialogInterface.OnKeyListener(){
@Override
public boolean onKey(DialogInterface dialog, int keyCode,KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
Log.i(TAG,"KEYCODE_BACK");
return true;
return false;
});
這樣運作後,出錯如下:
10-18 13:27:06.380: ERROR/AndroidRuntime(4684): Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRoot$W@2b046d68 -- permission denied for this window type
其實,隻需要把dialog.getWindow().setType的位置放在show後面就可以了
這麼,就完成了Back鍵的屏蔽 和Home鍵盤的屏蔽了!
總結:
1:)在以上用WindowManager.LayoutParams.TYPE_KEYGUARD的地方改用
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG 效果一樣。至于兩者的具體差别,得以後再研究研究。
2:)其實,在源碼裡是這樣調用的。
final AlertDialog dialog = new AlertDialog.Builder(mContext)
.setTitle(null)
.setMessage(message)
.setNeutralButton(R.string.ok, null)
.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
但我們如果這樣調用就會出現之前的那個error:permission denied for this window type 這就顯而易見了吧~~
3:)ProgressDialog 預設屏蔽 Back鍵,Dialog,AlertDialog則需setOnKeyListener
4:)其實屏蔽Home鍵,在頁面的某個地方,例如一個Button的onClick裡,去設定setType就可以了,如:
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);
});
但前提是重載Activity的onAttachedToWindow(),哪怕隻是一個空實作,然後傳回父類方法。
@Override
5:)其實它們,都是常用的~
switch (keyCode) {
case KeyEvent.KEYCODE_HOME:
Log.i(TAG,"KEYCODE_HOME");
case KeyEvent.KEYCODE_BACK:
case KeyEvent.KEYCODE_CALL:
Log.i(TAG,"KEYCODE_CALL");
case KeyEvent.KEYCODE_SYM:
Log.i(TAG,"KEYCODE_SYM");
case KeyEvent.KEYCODE_VOLUME_DOWN:
Log.i(TAG,"KEYCODE_VOLUME_DOWN");
case KeyEvent.KEYCODE_VOLUME_UP:
Log.i(TAG,"KEYCODE_VOLUME_UP");
case KeyEvent.KEYCODE_STAR:
Log.i(TAG,"KEYCODE_STAR");
希望大家看到這個文章能覺得有用,謝謝已閱者!
2011-10-20 更新如下:
總結1:)的問題,有答案了,時間問題我就簡單寫寫吧:
從功能上來說,是一樣的,差別在樣式。
如果你喜歡用Theme.Dialog去把一個Activity裝飾成一個Dialog去顯示,你會發現。
在
android:theme="@android:style/Theme.Dialog"
背景是透明的。
如果在
setTheme(android.R.style.Theme_Dialog);
背景則是黑色的。
這是為什麼呢?。。。我不知道。
治标不治本的方法來了!若你在Activity重寫onAttachedToWindow
this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
那麼出來的效果,就是透明背景的dialog了,當然前提是你需要實作屏蔽Home鍵。至于其中到底哪一代碼導緻樣式改變呢,那就以後再去看源代碼了~