Android設置界面層級為最上層實現
文章目錄
- Android設置界面層級為最上層實現
- 一、前言
- 二、Android設置界面層級為最上層實現
- 1、主要代碼
- 2、后遺癥
- 三、其他
- 1、Android設置界面層級為最上層小結
- 2、懸浮框的主要代碼
- 懸浮框 注意事項
- (1)權限限制
- (2)懸浮框窗口類型
- (3)懸浮框窗口管理
- Activity添加懸浮框后關閉Activity的情況,沒有Activity,沒有Service,這個應用是存活的,為啥呢?
- 關鍵窗口類型對比:
- (4)懸浮框的正常使用
- (5)查看當前頂層界面信息
- (6)查看當前所有窗口
- 3、Android對話框的使用總結
- 4、Android 幾個簡單的自定義對話框介紹
一、前言
Android設置界面層級為最上層怎么實現?
正常情況設置懸浮框就可以了,懸浮框默認是最上層的。
但是Java還有個地方的代碼可以設置界面再任何界面之上;
具體實現邏輯沒有去分析,這個只是其他人這樣分析實現了,我順便記錄一下。
真正用到的場景估計比較少,有些系統應用的唯一懸浮框界面估計會需要用到;
最后也介紹到了一些懸浮框相關的小眾知識,有興趣的可以看看。
二、Android設置界面層級為最上層實現
1、主要代碼
frameworks\base\services\core\java\com\android\server\wm\Task.java
@Overridepublic boolean isAlwaysOnTop() {boolean isinstallCts = SystemProperties.getBoolean("persist.skg.isinstall.cts", false);if (!isinstallCts) {// debug settings return trueString pk = getBasePackageName();if (pk.equals("com.debug.dialog") || pk.equals("com.android.settings") ) {return true;}}return !isForceHidden() && super.isAlwaysOnTop();}
修改上面代碼后就可以實現top的包名應用會出現在最上層;
即使懸浮框和對話框都是顯示在它的下層。
如果兩個應用同時是top,后面拉起的一個會顯示在最上層。
實現原理這里不進行分析了,因為我沒研究過!
2、后遺癥
按照上面的修改會有點問題:
如果只是懸浮框顯示在最上層,并且可以移動,交互上是沒啥問題的;
如果最上層的是Activity 界面,按Home和后臺任務無效,未添加堆棧前返回按鍵無法關閉界面;
因為Home之后的Launcher界面的優先級也比它低;
后臺任務的界面優先級也比它低。
所以只有是懸浮框的應用或特定的系統界面可以采用這種方式設置方式設置界面層級最高級;
其他情況慎用。
三、其他
1、Android設置界面層級為最上層小結
本文是強制設置某個應用的界面為最頂層。一般不建議這樣修改。
簡單的理解每個界面顯示系統都會判斷它的級別,隨后排序顯示顯示。
普通懸浮于應用的場景,使用系統懸浮框就可以了。
大致優先級:top>懸浮框>對話框>Activity.
如果是鎖屏界面呢?在top上面還是下面?
試了一下,鎖屏界面是在top應用界面上面的。鎖屏界面的層級不清楚怎么樣的。
2、懸浮框的主要代碼
// 獲取 WindowManager 服務WindowManager windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);// 設置 WindowManager 布局參數WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.WRAP_CONTENT,WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, //懸浮框類別WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,android.graphics.PixelFormat.TRANSLUCENT);//floatingView 是某個layout對象,不能是普通的view,比如TextViewwindowManager.addView(floatingView, params);//移除它
windowManager.removeView(floatingLayout)
floatingView 示例:
//正確示例:
LinearLayout floatingView = (LinearLayout) View.inflate(this, R.layout.activity_main, null);//錯誤示例(傳入這個floatingView會報錯):
LinearLayout floatingView = findViewById(R.id.activity_demo);
懸浮框 注意事項
(1)權限限制
從 Android 6.0 (API 23) 開始,必須通過 Settings.ACTION_MANAGE_OVERLAY_PERMISSION
顯式請求懸浮窗權限。
部分廠商定制系統可能進一步限制此權限。
(2)懸浮框窗口類型
-
Android 8.0 (API 26) 及以上版本必須使用
TYPE_APPLICATION_OVERLAY
類型。 -
舊版本使用
TYPE_PHONE
或TYPE_SYSTEM_ALERT
。 -
TYPE_SYSTEM_ALERT 在新版本也能使用,但是必須是系統簽名權限應用。
-
系統系統應用不常用窗口類別:
這些類型用于系統組件,普通應用通常無法使用: TYPE_STATUS_BAR 描述:狀態欄窗口。 TYPE_NAVIGATION_BAR 描述:導航欄窗口。 TYPE_INPUT_METHOD 描述:輸入法窗口。 TYPE_KEYGUARD 描述:鎖屏界面窗口。 TYPE_ACCESSIBILITY_OVERLAY 描述:無障礙服務覆蓋窗口。 TYPE_DREAM 描述:屏保窗口(Doze 模式)。 TYPE_VOICE_INTERACTION 描述:語音交互窗口(如 Google Assistant)。
-
窗口類型的層級關系(從低到高):
應用界面 < TYPE_APPLICATION_OVERLAY < TYPE_SYSTEM_ALERT < 狀態欄 < 輸入法 < 系統錯誤窗口
上面的窗口類別了解一下就可以了,有些窗口類別是需要再特定條件下才能使用的。
(3)懸浮框窗口管理
WindowManager 添加的懸浮框窗口,后面的窗口不屬于應用了?
如果是demo應用的Activity添加的懸浮框,Activity界面退出后,懸浮框窗口還是會顯示在系統界面上;
那么這個時候demo應用還存活嗎?
使用命令:“ps -ef | grep XXX包名” 查看了一下,應用進程是在的;
即使使用后臺進程列表,去除該應用,發現應用進程還在,懸浮窗口還是存在;
這種情況應該是系統清除進程過程判斷當前應用有關聯的窗口,所以沒有kill應用進程;
使用命令 “ am force-stop XXX包名”,kill進程后,懸浮框確實關閉了。
所以說懸浮框窗口顯示的前提必須要原本拉起懸浮窗口的應用必須存活。
Activity添加懸浮框后關閉Activity的情況,沒有Activity,沒有Service,這個應用是存活的,為啥呢?
這個和系統進程策略有關,有些系統列表的窗口就是可以不依賴Activity存在。
為啥沒有Activity也能存活,具體是哪個類哪個邏輯的處理,我也不清楚!
關鍵窗口類型對比:
窗口類型 | 所屬層級 | 是否允許后臺存在(無 Activity/Service) |
---|---|---|
TYPE_APPLICATION | 應用層級 | 不允許:依賴 Activity 存在 |
TYPE_APPLICATION_OVERLAY | 應用覆蓋層級 | 允許:可在后臺獨立存在(需權限) |
TYPE_SYSTEM_ALERT | 系統層級 | 允許:系統級窗口,可后臺存在 |
TYPE_APPLICATION 類別的窗口,和對話框是一樣類型的,不太算懸浮框了。
(4)懸浮框的正常使用
正常情況下,懸浮框的使用都是在Service拉起的,并且可以在Service實時監聽數據變化更新界面顯示。
(5)查看當前頂層界面信息
//普通應用正常運行,查看當前頂層界面信息
console:/ # dumpsys window | grep mFocmFocusedApp=ActivityRecord{3609e53 u0 com.example.an15/.MainActivity t66}mFocusedWindow=Window{4e5b6fa u0 com.example.an15/com.example.an15.MainActivity}
console:/ #
console:/ #
//Activity退出,懸浮框界面顯示的時候
console:/ # dumpsys window | grep mFocmFocusedApp=ActivityRecord{85383ad u0 com.android.launcher3/.uioverrides.QuickstepLauncher t63}mFocusedWindow=Window{c1dff8 u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
可以看到顯示懸浮框界面的時候,當前頂層界面是懸浮框背后的界面,
如果是桌面應用,就是Launcher界面了。
(6)查看當前所有窗口
查看當前所有窗口命令:dumpsys window windows | grep “Window{”
這個命令能看到:當前頂層窗口,懸浮窗口,系統其他窗口信息等。
示例如下:
//*************顯示懸浮窗,并且未關閉demo應用的Activity前
console:/ #
console:/ # dumpsys window windows | grep "Window{" Window #0 Window{6c3345b u0 ScreenDecorOverlayBottom}:...//添加的懸浮窗口信息Window #5 Window{f3d263 u0 Sys2038:com.example.an15/com.example.an15.MainActivity}:Window #6 Window{e3472f4 u0 ShellDropTarget}:Window #7 Window{d2f67df u0 InputMethod}://當前的頂層界面信息,demo應用Window #8 Window{365bc0c u0 com.example.an15/com.example.an15.MainActivity}://其他界面信息,比如Launcher 、后臺未關閉的窗口Window #9 Window{8b073fa u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}:Window #10 Window{c4d9262 u0 com.android.systemui.wallpapers.ImageWallpaper}:
...
console:/ # //***********顯示懸浮窗,并且已關閉demo應用的Activity后,顯示的是Launcher桌面
console:/ #
console:/ # dumpsys window windows | grep "Window{" Window #0 Window{6c3345b u0 ScreenDecorOverlayBottom}://添加的懸浮窗口信息Window #5 Window{f3d263 u0 Sys2038:com.example.an15/com.example.an15.MainActivity}:Window #6 Window{e3472f4 u0 ShellDropTarget}:Window #7 Window{d2f67df u0 InputMethod}://當前的頂層界面信息,Launcher應用Window #8 Window{8b073fa u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}://其他信息界面Window #9 Window{c4d9262 u0 com.android.systemui.wallpapers.ImageWallpaper}:imeLayeringTarget in display# 0 Window{8b073fa u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}imeInputTarget in display# 0 Window{8b073fa u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
console:/ #
從window窗口信息,可以大致看到,window的次序信息和界面顯示的是大致一致的;
前面先是顯示懸浮窗口,后面顯示應用窗口;
應用的懸浮窗口信息比較明顯,包含了包名,其他的懸浮窗口,是一些系統的懸浮窗口信息;
懸浮窗口后面的信息,就到普通應用的Activity界面了,
第一個非懸浮窗口界面就是當前的頂層界面,后面的界面就是后臺存在的界面了;
應用界面打開后,按Home返回,所有后臺應用界面都會顯示在上面;
不排除系統判斷當前應用進程太多的情況,會殺死一些應用界面。
以前看這個信息也沒注意這么多,現在看看dumpsys這些window信息對界面分析還是比較有用的。
3、Android對話框的使用總結
(一)警告對話框 AlertDialog: 一個可以有0到3個按鈕, 一個單選框或復選框的列表的對話框. 警告對話框可以創建大多數的交互界面, 是推薦的類型.
(二)進度對話框 ProgressDialog: 顯示一個進度環或者一個進度條. 由于它是AlertDialog的擴展, 所以它也支持按鈕.
(三)日期選擇對話框 DatePickerDialog: 讓用戶選擇一個日期.
(四)時間選擇對話框 TimePickerDialog: 讓用戶選擇一個時間
原文鏈接:https://blog.csdn.net/wenzhi20102321/article/details/52818351
4、Android 幾個簡單的自定義對話框介紹
Android 對話框直接使用肯定是不好看的,如果需要添加取消和確定按鈕,肯定是需要進行自定義修改的。
簡單介紹一個簡單的可擴展的對話框,并且支持不同類型樣式,加了點小動畫。
https://blog.csdn.net/wenzhi20102321/article/details/139040977