Android ウィンドウ レベル (ウィンドウ タイプ) の分析

序文

Android のウィンドウは次の 3 種類に分類されます。

アプリケーション ウィンドウ (例Activity:Dialog子ウィンドウ) PopupWindow; システム ウィンドウ (Toastシステム ステータス バー、ナビゲーション バーなど)

アプリケーション ウィンドウの Z オーダーは最も低く、システム内で最も低い表示レベルを持ち、その後サブ ウィンドウに進み、最も高いレベルがシステム ウィンドウになります。より高いレベルのウィンドウは、より低いレベルのウィンドウを上書きします。ウィンドウを重ねて表示するには、そのウィンドウを前のウィンドウよりも高いレベルにするだけです。

3 種類のウィンドウはそれぞれに対応していますWindowToken。各アプリケーション コンポーネント (アプリケーション コンポーネントはActivityなど、各コンポーネントは 1 つに対応します) を WMS に適用してウィンドウを追加する必要がありますInputMethod。WMS ( ) はウィンドウの分類に従って編成されています. 同じウィンドウは密接に関連しています。アプリケーション コンポーネントは、新しいウィンドウを作成するときに、サーフェス ウィンドウ ID タイプを提供する必要がありますシステム ウィンドウはそれを暗黙的に宣言し、WMS は同時にそれを認証します。WallpaperWindowTokenWindowTokenWindowManagerSerivceWindowTokenWindowTokenWindowTokenWindowTokenaddWindow()

アプリケーションウィンドウの階層

アクティビティ表示

ソースコードから始めましょうActivity:ソースコードsetContentView()
ここに画像の説明を挿入します
AppCompatDelegateImpl
ここに画像の説明を挿入します

mSubDecorWindow ではなく、DecorView作成DecorView後に作成された子はDecorView、 が含まれているかどうかも含めてActionBarFloatingActionButton旧バージョンDecorViewと同等ですTitleBar

getWindow()Activity返された変数で、抽象クラスであるオブジェクトmWindowを指します。ここで返されるのはオブジェクト (のサブクラス) です。にはオブジェクトがあり、実際にはのサブレイアウトであり、最終的に現在のレイアウトに追加されます。ウィンドウのルートビュー。WindowWindowPhoneWindowPhoneWindowWindowPhoneWindowDecorViewDecorViewFrameLayoutsetContentView()DecorViewDecorView

このルートビューは最終的にどのように描画されるのでしょうか?

WindowView直接のマネージャである抽象ウィンドウの概念を表し、 が1 つに対応しViewWindowView接続されますViewRootImpl

ActivityレベルViewは次のとおりです。
ここに画像の説明を挿入します

アプリケーションウィンドウの階層タイプ

WMS がアプリケーション ウィンドウをオーバーレイすると、アプリケーション ウィンドウのレイヤー値が動的に変更されますが、レイヤー値は 99 を超えることはありません。

public static final int FIRST_APPLICATION_WINDOW = 1;
public static final int TYPE_BASE_APPLICATION = 1;
public static final int TYPE_APPLICATION = 2;
public static final int TYPE_APPLICATION_STARTING = 3;
public static final int TYPE_DRAWN_APPLICATION = 4;
public static final int LAST_APPLICATION_WINDOW = 99;

1.Activityデフォルトのウィンドウ レベルは ですTYPE_BASE_APPLICATIONウィンドウにWindowManager.addView()追加することで。DecorViewこのコードは次の場所にありますActivityThread

ここに画像の説明を挿入します
2.Dialogデフォルトのレベルは次のとおりですTYPE_APPLICATION
Dialog:
1. ウィンドウを作成します (方法はアクティビティの作成と同じです);
2.DecorViewダイアログ ビューを初期化して追加しますDecorView;
3.DecorView表示するためにウィンドウに追加します。
階層的な構築方法もありますウィンドウ タイプが指定されていない場合、デフォルトは です。したがって、で作成する場合、ウィンドウ タイプが指定されていない場合、デフォルトは ですで作成してポップアップすると同じコードがエラーを報告します。正常に表示するには、システム ウィンドウ レベルより上に設定する必要があります。TYPE_APPLICATIONActionMode
WindowmanagerLayoutParamsTYPE_APPLICATIONDialogActivityTYPE_APPLICATION
ここに画像の説明を挿入します
ServiceDialogActivityWindowManager.LayoutParams.TYPE_SYSTEM_ALERT

3.TYPE_APPLICATION_STARTING起動ウィンドウの Z-Ordered は、アプリケーション内の他のすべてのウィンドウよりも上位にある必要があります。Android 12独自の起動画面StartingWindowを搭載SplashScreenこれには、SystemUIWMShellコンポーネントも含まれます。その中には、SplitScreen 分割画面モード、OneHanded 片手モード、Freeform フリー ウィンドウ モード、バブル通知ウィンドウ (Android Q)、PIP ピクチャ イン ピクチャ モード、およびその他のシステム モード ウィンドウが処理の一部です。WMShell

  1. アプリケーションでToast一時的なポップアップを作成することがよくありますが、Toastそれはアプリケーション ウィンドウではなくシステム ウィンドウであり、レベルは でありTYPE_TOAST、アプリケーション ウィンドウの範囲内ではありません。以下のシステムウィンドウで紹介されます。

サブウィンドウレベル(サブウィンドウ)

       public static final int FIRST_SUB_WINDOW = 1000;
       public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;
       public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;
       public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;
       public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;
       public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW + 4;
       public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;
       public static final int LAST_SUB_WINDOW = 1999;

子ウィンドウのタイプは、アプリケーション ウィンドウにアタッチされたウィンドウに設定する必要があります。これらのタイプのウィンドウは、それらがアタッチされているウィンドウの隣で Z オーダーのままであり、その座標はそれらがアタッチされているアプリケーション ウィンドウを基準としています。

1.TYPE_APPLICATION_PANELパネルのサブウィンドウの場合、PopupWindow
PopupWindowソース コードで指定されたウィンドウ レベルなど、ウィンドウの上部にパネルを適用します。

  private int mWindowLayoutType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;

2.TYPE_APPLICATION_MEDIAメディア (ビデオなど) を表示するウィンドウ。Android 7.1以前のSurfaceViewソースコードにおけるデフォルトのレベル、SurfaceViewソースコードにおけるsetZOrderOnTop()メソッド、およびSurfaceView設定されている表示順序です。

  public void setZOrderOnTop(booleanonTop) {
    
    
       if (onTop) {
    
    
           mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
           // ensures the surface is placed below the IME
           mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
       } else {
    
    
           mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
           mLayout.flags&= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
       }
   }

3.TYPE_APPLICATION_MEDIA_OVERLAY隠しタイプのため、アプリケーションから直接呼び出すことはできません。Android 7.1 より前のSurfaceViewソース コードにも含まれています。

       public void setZOrderMediaOverlay(booleanisMediaOverlay) {
    
    
           mWindowType = isMediaOverlay
                   ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
                   : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
       }

4.TYPE_APPLICATION_SUB_PANELアプリケーションウィンドウのサブパネルは、ポップアップリストやポップアップエディットボックスなどTYPE_APPLICATION_PANELの上位層を表します。PopupWindowEditor

5.TYPE_APPLICATION_ATTACHED_DIALOG同様ですTYPE_APPLICATION_PANELが、ウィンドウのレイアウトは、コンテナの子ウィンドウとしてではなく、トップレベル ウィンドウのレイアウトとして発生します。たとえばCharacterPickerDialogPhoneWindowソースコードopenPanel()メソッドではこのタイプを使用していますが、Android 7.1 以降では異なります。どちらの値も 0 未満で、現在の表示ウィンドウの下層にあることを意味します: 6. 非表示の
ここに画像の説明を挿入します
タイプTYPE_APPLICATION_ABOVE_SUB_PANELはサブパネルと、アプリケーション ウィンドウの上にあるそのサブパネル。パネル ウィンドウ。これらのウィンドウは、TYPE_APPLICATION_SUB_PANEL接続されているウィンドウおよびパネルの上に表示されます。

システムウィンドウレベル

開発中に、ウィンドウは次のように追加されることがよくあります。

mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); 
mLayoutParams = new WindowManager.LayoutParams(); 
mLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; mLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; 
mLayoutParams.format = PixelFormat.RGBA_8888; 
mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; mLayoutParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; 
mLayoutParams.type = WindowManager.LayoutParams. TYPE_APPLICATION_OVERLAY;
mWindowManager.addView(view, mLayoutParams);

注: TYPE_APPLICATION_OVERLAY は Android 8 で追加されたタイプです

この方法で追加されたウィンドウはすべてシステム ウィンドウであり、ウィンドウのアクセス許可も必要です。

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

システム ウィンドウの階層タイプは次のとおりです。

窓の種類 説明する
FIRST_SYSTEM_WINDOW システム ウィンドウ タイプ、開始値 2000
TYPE_STATUS_BAR ステータスバー。ステータス バー ウィンドウは 1 つだけ画面の上部に配置でき、他のすべてのウィンドウは下に移動して画面の下に表示されます。フルスクリーンはパラメータで設定できます。
TYPE_SEARCH_BAR 検索バー。検索バー ウィンドウは 1 つだけ、画面の上部にのみ存在できます。ステータスバーに表示
TYPE_PHONE 着信などの電話ウィンドウ。アプリ ウィンドウの上、ステータス バーの後ろ。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください
TYPE_SYSTEM_ALERT バッテリ低下警告ポップアップ ボックスなどのシステム警告ウィンドウ。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください。
TYPE_KEYGUARD ロック画面ウィンドウ。参照されたインターフェイスは生成されません。
TYPE_TOAST トースト一時通知ウィンドウ。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください。
TYPE_SYSTEM_OVERLAY システム オーバーレイ ウィンドウは、他のすべてのウィンドウの上に表示する必要があります。これらのウィンドウは入力フォーカスを持つことができないため、ロック画面に干渉する可能性があります。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください。
TYPE_PRIORITY_PHONE ロック画面がアクティブな場合でも表示する必要があるモバイル UI を優先します。これらのウィンドウは入力フォーカスを持つことができないため、ロック画面に干渉する可能性があります。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください。
TYPE_SYSTEM_DIALOG ステータスバーからスライドして現れるパネル。
TYPE_KEYGUARD_DIALOG 画面ロック時に表示されるダイアログ。
TYPE_SYSTEM_ERROR システムエラーウィンドウ。廃止されました。代わりに TYPE_APPLICATION_OVERLAY を使用してください。
TYPE_INPUT_METHOD 入力方法ウィンドウ。通常の UI の上に表示されます。アプリケーション ウィンドウのサイズを変更したりパンしたりして、ウィンドウの表示中に入力フォーカスを表示したままにすることができます。
TYPE_INPUT_METHOD_DIALOG 入力方法ダイアログ ウィンドウは、現在の入力方法ウィンドウの上に表示されます。
TYPE_WALLPAPER 壁紙ウィンドウ。壁紙の窓の後ろに表示したいレベルに配置します。このシステムには壁紙サービスがあり、壁紙に対応する TOKEN を使用してウィンドウを特別に調整できます。
TYPE_STATUS_BAR_PANEL SystemUIDialog、SystemUI の HeadsUpView など、ステータス バーからスライドして表示されるパネル。生成されないAPPによって使用されるタイプ
TYPE_SECURE_SYSTEM_OVERLAY セキュリティ システム オーバーレイ ウィンドウは、他のすべてのウィンドウの上に表示する必要があります。これらのウィンドウは入力フォーカスを持つことができないため、ロック画面に干渉する可能性があります。これは、システム自体のみがこれらのオーバーレイの作成を許可されることを除いて、TYPE_SYSTEM_OVERLAY とまったく同じです。アプリケーションはセキュリティ システム オーバーレイを作成する権限を取得できません。隠しタイプ
TYPE_DRAG 疑似ウィンドウをドラッグ アンド ドロップします。ドラッグ レイヤは最大 1 つあり、他のすべてのウィンドウの上に配置されます。隠しタイプ
TYPE_STATUS_BAR_SUB_PANEL ステータス バーからスライドするパネルがすべてのユーザーのウィンドウに表示されます。これらのウィンドウは、ステータス バーおよび TYPE_STATUS_BAR_PANEL ウィンドウの上部に表示されます。たとえば、メソッドSystemUIDialogを通じてsetWindowOnTop()TYPE_STATUS_BAR_PANEL の TYPE_STATUS_BAR_SUB_PANEL 表示レベルを切り替えます。隠しタイプ
タイプポインター マウスカーソル。隠しタイプ
タイプナビゲーションバー ナビゲーションバー。隠しタイプ
タイプ_ボリューム_オーバーレイ ユーザーがシステムボリュームを変更するときに表示されるボリュームレベルダイアログボックス。隠しタイプ
タイプ_ブート_プログレス すべての上に進行状況ダイアログを起動します。隠しタイプ
TYPE_INPUT_CONSUMER システム UI バーが非表示のときに使用される入力イベントのウィンドウ タイプ。隠しタイプ
TYPE_NAVIGATION_BAR_PANEL ナビゲーション バー パネル (ナビゲーション バーがステータス バーと異なる場合)。隠しタイプ
TYPE_DISPLAY_OVERLAY オーバーレイウィンドウを表示します。セカンダリ ディスプレイ デバイスをシミュレートするために使用されます。隠しタイプ
TYPE_MAGNIFICATION_OVERLAY オーバーレイウィンドウを拡大します。アクセシビリティ拡大が有効な場合に、表示の拡大部分を強調表示するために使用されます。隠しタイプ
TYPE_PRIVATE_PRESENTATION プライベートトッププレゼンテーションウィンドウ。プレゼンテーションは、対応する表示パラメータ FLAG_PRIVATE に従って設定されます。
TYPE_VOICE_INTERACTION 音声対話ウィンドウ。隠しタイプ
TYPE_ACCESSIBILITY_OVERLAY 由连接的AccessibilityService覆盖的窗口,用于拦截用户交互,而无需更改可访问性服务可以内省的窗口。特别是,可访问性服务只能内省有视力的用户可以与之交互的窗口,即他们可以触摸这些窗口或在这些窗口中键入内容。例如,如果有一个可触摸的全屏辅助功能覆盖,则辅助功能服务将对其下方的窗口进行内省,即使它们被可触摸窗口覆盖。
TYPE_VOICE_INTERACTION_STARTING 语音交互层的启动窗口。
TYPE_DOCK_DIVIDER 用于显示用于调整堆栈大小的句柄的窗口。此窗口由系统进程所有。隐藏的类型
TYPE_QS_DIALOG 类似于 TYPE_APPLICATION_ATTACHED_DIALOG,但由快速设置平铺使用。隐藏的类型
TYPE_SCREENSHOT 屏幕截图。截取之下的窗口层级。如果采用android远程的层级截图无法截取倒车相关的UI视图。隐藏接口。
TYPE_PRESENTATION 外部显示器上的演示窗口。隐藏的类型
TYPE_APPLICATION_OVERLAY 用程序覆盖窗口显示在所有活动窗口上方(类型介于 FIRST_APPLICATION_WINDOW和 LAST_APPLICATION_WINDOW之间),但显示在状态栏或IME等关键系统窗口下方。系统可以随时改变这些窗口的位置、大小或可见性,以减少用户的视觉混乱,并管理资源要android.Manifest.permissionSYSTEM_ALERT_WINDOW权限。系统将调整具有此窗口类型的进程的重要性,以减少低内存杀手杀死它们的机会
TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY 用于在其他窗口之上添加辅助功能窗口放大倍数的窗口。这将把窗口放置在覆盖窗口中。隐藏的类型
TYPE_NOTIFICATION_SHADE 锁屏时通知效果。只能有一个状态栏窗口;它被放置在屏幕的顶部,所有其他窗口都向下移动,所以它们都在屏幕的下面。隐藏的类型
TYPE_STATUS_BAR_ADDITIONAL 画面の通常とは異なる部分 (つまり、画面の左側または下側) にステータス バーを表示するために使用されます。隠しタイプ
LAST_SYSTEM_WINDOW システムウィンドウタイプの最高レベル 2999

以下は Android 1 から始まるウィンドウ レベルです。初期の 10 以上から現在では 40 以上に発展し、さらに多くのウィンドウ レベルがあります。
ここに画像の説明を挿入します

カスタムウィンドウ階層

車載ソリューションでは反転などの特殊なインターフェースを上位のウィンドウレベルで表示する必要があり、Android本来のウィンドウレベルでは車載のニーズを満たしていないため、車載のウィンドウレベルをカスタマイズすることになります。

以下の図は、参考用のカスタム ウィンドウ階層を示しています。
ここに画像の説明を挿入します

システムはウィンドウ レベルをカスタマイズできます。フレームワークの変更については、別のブログ「
Android カスタム ウィンドウ レベル (車両システムの反転画像表示レベルのカスタマイズ)」を参照してください。

カスタム ウィンドウ レベルの初期レベル値も Android バージョンによって異なるため、SystemProperties.getInt("ro.custom.window", 2041)初期値はシステム プロパティを通じて決定する必要があります。
たとえば、Android 13 プラットフォームのデフォルト属性はro.custom.window2401 ですが、Android 9 およびその他のプラットフォームでは 2031 です。これの目的は、Android のネイティブ ウィンドウ階層と競合するため、プラットフォームに応じて初期値を調整する必要があります。
TYPE_CUSTOM_FIRST_WINDOW()Android のネイティブ ウィンドウ レベルより上の、初期システム ウィンドウ レベルをカスタマイズするには

TYPE_TOP_BAR以降TYPE_BOTTOM_BARTYPE_CUSTOM_FIRST_WINDOWただし、逆インターフェースの下に表示されます。
TYPE_REVERSE_WINDOW反転画像のウィンドウ レベル。逆をカバーするには、より高いレベルを使用するか、逆が表示された後にそれを追加する必要がありますTYPE_CUSTOM_LAST_WINDOW

おすすめ

転載: blog.csdn.net/CJohn1994/article/details/132794066
おすすめ