dialog,activity 屏蔽Home鍵詳解

相信在Android應用上,不少時候邏輯是須要屏蔽Home鍵的,但這個用戶體驗是否須要,就看各位的需求了。 
    通常的方法屏蔽Home鍵,你們必定看過很多文章了。我總結一下,先說一下通常狀況下Activity的屏蔽按鍵和Home鍵吧。 
屏蔽其餘鍵,重寫onKeyDown  
Java代碼   收藏代碼
  1. @Override  
  2. public boolean onKeyDown(int keyCode, KeyEvent event) {  
  3.     Log.i(TAG,"keycode="+keyCode + "   isBan="+isBan);  
  4.     switch (keyCode) {  
  5.         case KeyEvent.KEYCODE_BACK:  
  6.         Log.i(TAG,"KEYCODE_BACK");  
  7.         return true;  
  8.     }  
  9.     return super.onKeyDown(keyCode, event);  
  10. }  

你們會發現,這裏屏蔽Home鍵是捕捉不到的,由於你們的權限通常是User因此是無效的。 
而其實android處理Home鍵等系統級按鍵是有必定的處理的。 
引用
看看源碼是怎樣處理的 \frameworks\policies\base\phone\com\android\internal\policy\impl\PhoneWindowManager.java #1092
Java代碼   收藏代碼
  1. // First we always handle the home key here, so applications  
  2. // can never break it, although if keyguard is on, we do let  
  3. // it handle it, because that gives us the correct 5 second  
  4. // timeout.  
  5. if (code == KeyEvent.KEYCODE_HOME) {  
  6.   
  7.     // If a system window has focus, then it doesn't make sense  
  8.     // right now to interact with applications.  
  9.     WindowManager.LayoutParams attrs = win != null ? win.getAttrs() : null;  
  10.     if (attrs != null) {  
  11.         final int type = attrs.type;  
  12.         if (type == WindowManager.LayoutParams.TYPE_KEYGUARD  
  13.            || type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) {  
  14.             // the "app" is keyguard, so give it the key  
  15.             return false;  
  16.         }  
  17.         final int typeCount = WINDOW_TYPES_WHERE_HOME_DOESNT_WORK.length;  
  18.         for (int i=0; i<typeCount; i++) {  
  19.             if (type == WINDOW_TYPES_WHERE_HOME_DOESNT_WORK[i]) {  
  20.                 // don't do anything, but also don't pass it to the app  
  21.                 return true;  
  22.             }  
  23.         }  
  24.     }  

經過源碼,咱們不難發現兩個的參數 WindowManager.LayoutParams.TYPE_KEYGUARD和 
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG 
借鑑於此,重寫onAttachedToWindow,以實現屏蔽Home鍵
Java代碼   收藏代碼
  1. public void onAttachedToWindow() {  
  2.     this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);  
  3.     super.onAttachedToWindow();  
  4. }  

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 華麗的分界線,如下內容更精彩- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

輪到dialog了,若是在Activity彈出dialog,在Activity設置以上2個方法是沒辦法屏蔽的。 
其實,原理是同樣的,只是地方不同而已。 
Java代碼   收藏代碼
  1. final Dialog dialog = new Dialog(this);  
  2. dialog.setContentView(R.layout.mydailog);  
  3. dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);  
  4. dialog.show();  
  5.   
  6. dialog.setOnKeyListener(new android.content.DialogInterface.OnKeyListener(){  
  7.     @Override  
  8.     public boolean onKey(DialogInterface dialog, int keyCode,KeyEvent event) {  
  9.         switch (keyCode) {  
  10.             case KeyEvent.KEYCODE_BACK:  
  11.             Log.i(TAG,"KEYCODE_BACK");  
  12.             return true;  
  13.         }  
  14.         return false;  
  15.     }  
  16. });   

這樣運行後,出錯以下: 
Error代碼   收藏代碼
  1. 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後面就能夠了 
正確代碼   收藏代碼
  1. dialog.show();  
  2. dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);  

這麼,就完成了Back鍵的屏蔽 和Home鍵盤的屏蔽了! 

總結: 
1:)在以上用WindowManager.LayoutParams.TYPE_KEYGUARD的地方改用 
WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG 效果同樣。至於二者的具體差異,得之後再研究研究。 

2:)其實,在源碼裏是這樣調用的。
Java代碼   收藏代碼
  1. final AlertDialog dialog = new AlertDialog.Builder(mContext)  
  2.     .setTitle(null)  
  3.     .setMessage(message)  
  4.     .setNeutralButton(R.string.ok, null)  
  5.     .create();  
  6. dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  7. dialog.show();  

    但咱們若是這樣調用就會出現以前的那個error:permission denied for this window type 這就顯而易見了吧~~ 

3:)ProgressDialog 默認屏蔽 Back鍵,Dialog,AlertDialog則需setOnKeyListener 

4:)其實屏蔽Home鍵,在頁面的某個地方,例如一個Button的onClick裏,去設置setType就能夠了,如: 
Java代碼   收藏代碼
  1. button.setOnClickListener(new View.OnClickListener() {  
  2.     @Override  
  3.     public void onClick(View v) {  
  4.         getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD);  
  5.     }  
  6. });  

但前提是重載Activity的onAttachedToWindow(),哪怕只是一個空實現,而後返回父類方法。 
Java代碼   收藏代碼
  1. @Override    
  2. public void onAttachedToWindow() {  
  3.     super.onAttachedToWindow();  
  4. }  

5:)其實它們,都是經常使用的~
Java代碼   收藏代碼
  1. switch (keyCode) {  
  2.     case KeyEvent.KEYCODE_HOME:  
  3.         Log.i(TAG,"KEYCODE_HOME");  
  4.         return true;  
  5.     case KeyEvent.KEYCODE_BACK:  
  6.         Log.i(TAG,"KEYCODE_BACK");  
  7.         return true;  
  8.     case KeyEvent.KEYCODE_CALL:  
  9.         Log.i(TAG,"KEYCODE_CALL");  
  10.         return true;  
  11.     case KeyEvent.KEYCODE_SYM:  
  12.         Log.i(TAG,"KEYCODE_SYM");  
  13.         return true;  
  14.     case KeyEvent.KEYCODE_VOLUME_DOWN:  
  15.         Log.i(TAG,"KEYCODE_VOLUME_DOWN");  
  16.         return true;  
  17.     case KeyEvent.KEYCODE_VOLUME_UP:  
  18.         Log.i(TAG,"KEYCODE_VOLUME_UP");  
  19.         return true;  
  20.     case KeyEvent.KEYCODE_STAR:  
  21.         Log.i(TAG,"KEYCODE_STAR");  
  22.         return true;  
  23. }  


但願你們看到這個文章能以爲有用,謝謝已閱者! 

- - - - - - - - - - - - -  - - - - - - - - - - - - - - - - 華麗的分界線,如下內容更精彩- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

2011-10-20 更新以下: 
總結1:)的問題,有答案了,時間問題我就簡單寫寫吧: 
    從功能上來講,是同樣的,區別在樣式。 
    若是你喜歡用Theme.Dialog去把一個Activity裝飾成一個Dialog去顯示,你會發現。 
Androidmanifest.xml代碼   收藏代碼
  1. android:theme="@android :style/Theme.Dialog"  

背景是透明的。 
若是在
Android代碼   收藏代碼
  1. setTheme(android.R.style.Theme_Dialog);  

背景則是黑色的。 
這是爲何呢?。。。我不知道。 
治標不治本的方法來了!若你在Activity重寫onAttachedToWindow 
Java代碼   收藏代碼
  1. public void onAttachedToWindow() {  
  2.     this.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  3.     super.onAttachedToWindow();  
  4. }  

那麼出來的效果,就是透明背景的dialog了,固然前提是你須要實現屏蔽Home鍵。至於其中到底哪一代碼致使樣式改變呢,那就之後再去看源代碼了~ 
相關文章
相關標籤/搜索