WMS の全名は WindowManagerService であり、クライアントアプリの管理者であり、SystemServer プロセスに存在します。WMS は主にいくつかのことを管理します。
ウィンドウ管理
ウィンドウの追加、更新、削除を担当し、コア管理メンバーには DisplayContent
、WindowToken
、WindowState
が含まれます。
ウィンドウアニメーション
ウィンドウの切り替え時にアニメーションを追加でき、ウィンドウの切り替えをより自然にします。アニメーションは WMS のアニメーションサブシステムによって管理され、このシステムは WindowAnimator
です。
入力システムの中継
ユーザーがウィンドウに触れたり入力したりすると、InputManagerService がタッチイベントを処理し、WMS を介して適切なウィンドウにイベントを渡します(この時、WMS は 中継地点 です)。
Surface 管理
WMS はウィンドウの描画機能を持っていません。各ウィンドウには描画用の Surface があり、WMS は Surface の割り当てを担当します。
WMS の起動 - SystemServer#
WMS は WindowManagerService であり、システムサービスです。システムサービスといえば SystemServer を思い浮かべるので、WMS がどのように SystemServer によって呼び出されるかを見てみましょう。
SystemServer は WMS#main
メソッドを通じて WMS を起動します。
WMS を Context#WINDOW_SERVICE
(window)として ServiceManager に設定します。
起動した WMS オブジェクトを AMS サービスに設定します。
// SystemServer.java
private void run() {
... 省略部分
// サービスを開始します。
try {
t.traceBegin("StartServices");
startBootstrapServices(t);
startCoreServices(t);
// WMS は OtherServices で起動します
startOtherServices(t);
} catch (Throwable ex) {
... 省略 Log
throw ex;
} /* 省略 finally */
}
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
t.traceBegin("StartWindowManagerService");
// WMS はセンサーサービスが準備される必要があります
mSystemServiceManager.startBootPhase(t, SystemService.PHASE_WAIT_FOR_SENSOR_SERVICE);
// 1. WMS を起動します
wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore,
new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager);
// 2. ServiceManager にサービス "window" を追加します
ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false,
DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PROTO);
ServiceManager.addService(Context.INPUT_SERVICE, inputManager,
/* allowIsolated= */ false, DUMP_FLAG_PRIORITY_CRITICAL);
t.traceEnd();
// 3. AMS と関係を持ちます
t.traceBegin("SetWindowManagerService");
mActivityManagerService.setWindowManager(wm);
t.traceEnd();
} /* 省略 catch */
}
WMS が起動した後、onInitReady
、displayReady
、systemReady
を通じて WMS の後続のアクションを完了します(これらのメソッドは後で紹介します)。
// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
// 初期化準備
wm.onInitReady();
... 省略部分
try {
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
wm.systemReady();
} /* 省略 catch */
}
WMS - main 関数#
DisplayThread の Handler#runWithScissors
を通じて WMS オブジェクトを作成します(つまり、WMS を作成するスレッドは SystemServer スレッドとは異なります)。
Handler#runWithScissors
メソッドはロックを通じて同期タスクを達成し、この Runnable が最初に DisplayThread の Looper によって実行され、実行が完了した後に SystemServer のスレッドに戻ります。
// WindowManagerService.java
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm) {
// @ main メソッドを確認
return main(context, im, showBootMsgs, onlyCore, policy, atm,
new DisplayWindowSettingsProvider(), SurfaceControl.Transaction::new, Surface::new,
SurfaceControl.Builder::new);
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, ... 省略部分の引数) {
// 新しいスレッドを作成
DisplayThread.getHandler().runWithScissors(() ->
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
surfaceControlFactory), 0);
// runWithScissors 内の Runnable タスクが完了した後にのみ戻ります
return sInstance;
}
HandlerThread - Looper の作成#
// HandlerThread.java
public class HandlerThread extends Thread {
... 省略部分のメソッド
@Override
public void run() {
mTid = Process.myTid();
// このスレッド専用の Looper & MessageQueue オブジェクトを準備
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
// すべての待機スレッドに通知、Looper が作成されました
notifyAll();
}
Process.setThreadPriority(mPriority);
// Looper の準備が整いました
onLooperPrepared();
// ループを開始してメッセージタスクを処理し続けます
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
// スレッドが開始されている場合、looper が作成されるまで待機します。
synchronized (this) { // 現在のオブジェクトをロックとして使用
while (isAlive() && mLooper == null) {
try {
wait(); // Looper が作成されるまで
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
// 必要なときにのみ作成(ただしスレッドは安全ではありません)
public Handler getThreadHandler() {
if (mHandler == null) {
mHandler = new Handler(getLooper());
}
return mHandler;
}
}
DisplayThread - WMS オブジェクトの作成#
WMS は DisplayThread クラス内で起動され、DisplayThread は WMS の MainThread と言えます。
DisplayThread は安全な Handler を作成でき、その主な機能は 低遅延表示 に関連する操作を処理し、WindowManager、DisplayManager、InputManager のみが迅速な操作を実行できます。
上記から、DisplayThread は ServiceThread を継承している(そしてそれは HandlerThread を継承している)ため、run メソッドを実行する際に自動的に Looper オブジェクトが作成されます。HandlerThread が作成した Handler は安全ではないため、DisplayThread では自分で Handler を作成します(クラスロックを使用)。
// DisplayThread.java
public final class DisplayThread extends ServiceThread {
private static DisplayThread sInstance;
private static Handler sHandler;
// シングルトンパターン
private DisplayThread() {
// DisplayThread は重要な処理を実行しますが、これらは AnimationThread で実行されるものほど重要ではありません。
// したがって、優先度を1つ下げます。
super("android.display", Process.THREAD_PRIORITY_DISPLAY + 1, false /*allowIo*/);
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new DisplayThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
sHandler = new Handler(sInstance.getLooper());
}
}
public static DisplayThread get() {
// クラスロック
synchronized (DisplayThread.class) {
// DisplayThread オブジェクトを作成
ensureThreadLocked();
return sInstance;
}
}
// DisplayThread.class クラスロックを通じて安全に作成を達成
public static Handler getHandler() {
// クラスロック
synchronized (DisplayThread.class) {
// DisplayThread オブジェクトを作成
ensureThreadLocked();
return sHandler;
}
}
}
イベントを WMS に渡す方法は 2 つあります。
直接 WMS 関数を呼び出し、即時に送信します。
// WindowManagerService.java
@Override
public boolean isKeyguardLocked() {
// mPolicy のタイプは WindowManagerPolicy
return mPolicy.isKeyguardLocked();
}
DisplayThread の Looper を介してイベントを WMS スレッド(DisplayThread)に投げ入れます。
// WindowManagerService.java
final H mH = new H();
final class H extends android.os.Handler {
...
}
@Override
public void setAnimationScale(int which, float scale) {
if (!checkCallingPermission(android.Manifest.permission.SET_ANIMATION_SCALE,
"setAnimationScale()")) {
throw new SecurityException("Requires SET_ANIMATION_SCALE permission");
}
scale = fixScale(scale);
switch (which) {
case 0: mWindowAnimationScaleSetting = scale; break;
case 1: mTransitionAnimationScaleSetting = scale; break;
case 2: mAnimatorDurationScaleSetting = scale; break;
}
// 設定を永続化
mH.sendEmptyMessage(H.PERSIST_ANIMATION_SCALE);
}
UiThread クラス#
UiThread は DisplayThread とほぼ同じですが、dispose
メソッドが追加され、Looper を停止し、そのオブジェクトを終了(null に設定)します。initPolicy()
、systemReady()
で使用されます。
// UiThread.java
public final class UiThread extends ServiceThread {
private static final long SLOW_DISPATCH_THRESHOLD_MS = 100;
private static final long SLOW_DELIVERY_THRESHOLD_MS = 200;
private static UiThread sInstance;
private static Handler sHandler;
private UiThread() {
super("android.ui", Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
}
@Override
public void run() {
// UiThread が fg stune boost グループにいることを確認します
Process.setThreadGroup(Process.myTid(), Process.THREAD_GROUP_TOP_APP);
super.run();
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new UiThread();
sInstance.start();
final Looper looper = sInstance.getLooper();
looper.setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
looper.setSlowLogThresholdMs(
SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
sHandler = new Handler(sInstance.getLooper());
}
}
public static UiThread get() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (UiThread.class) {
ensureThreadLocked();
return sHandler;
}
}
/**
* 現在の ui スレッドを初期化されている場合に破棄します。新しい環境を設定するためにのみテストで使用する必要があります。
*/
@VisibleForTesting
public static void dispose() {
synchronized (UiThread.class) {
if (sInstance == null) {
return;
}
// runWithScissors が完了した後にのみ実行されます
getHandler().runWithScissors(sInstance::quit, 0 /* timeout */);
sInstance = null;
}
}
}
AnimationThread クラス#
AnimationThread は DisplayThread とほぼ同じですが、dispose
メソッドが追加され、Looper を停止し、そのオブジェクトを終了(null に設定)します。
// AnimationThread.java
public final class AnimationThread extends ServiceThread {
private static AnimationThread sInstance;
private static Handler sHandler;
private AnimationThread() {
super("android.anim", THREAD_PRIORITY_DISPLAY, false /*allowIo*/);
}
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new AnimationThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_WINDOW_MANAGER);
sHandler = new Handler(sInstance.getLooper());
}
}
public static AnimationThread get() {
synchronized (AnimationThread.class) {
ensureThreadLocked();
return sInstance;
}
}
public static Handler getHandler() {
synchronized (AnimationThread.class) {
ensureThreadLocked();
return sHandler;
}
}
// HandlerThread#quit メソッドを使用して Looper を停止します
@VisibleForTesting
public static void dispose() {
synchronized (AnimationThread.class) {
if (sInstance == null) {
return;
}
getHandler().runWithScissors(() -> sInstance.quit(), 0 /* timeout */);
sInstance = null;
}
}
}
SystemServer - WMS 起動後の続き#
// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
// 初期化準備
wm.onInitReady();
... 省略部分
try {
wm.displayReady();
} catch (Throwable e) {
reportWtf("making display ready", e);
}
wm.systemReady();
} /* 省略 catch */
}
WMS の作成#
前述の通り、WindowManagerService#main
メソッドは DisplayThread(スレッド)を通じて WMS のインスタンスを作成します。ここで H クラス が作成され、その Looper は現在のスレッド、つまり DisplayThread です。
// WindowManagerService.java
// Looper が指定されていない場合、現在のスレッドの Looper が使用されます
final H mH = new H(); // つまり DisplayThread の Looper
WindowManagerPolicy mPolicy;
final WindowAnimator mAnimator;
RootWindowContainer mRoot;
final class H extends android.os.Handler {
...
}
private WindowManagerService(Context context, InputManagerService inputManager,
boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
... 省略部分
// WMS は InputManagerService の参照を保持します
mInputManager = inputManager;
...
// DisplayManagerService の代理を取得
mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
mPolicy = policy; // SystemServer から渡されたインスタンスは PhoneWindowManager クラスです
// WMS の代理を取得
mActivityManager = ActivityManager.getService();
mActivityTaskManager = ActivityTaskManager.getService();
// ウィンドウアニメーション
mAnimator = new WindowAnimator(this);
// すべてのウィンドウのルートノード (RootWindowContainer オブジェクト)
mRoot = new RootWindowContainer(this);
}
WMS#onInitReady
- WindowManagerPolicy の初期化#
WMS#onInitReady
関数:UiThread (別のスレッド) の Handler を取得し、WindowManagerPolicy 実装の PhoneWindowManager#init 関数を呼び出します。
// WindowManagerService.java
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
WindowManagerPolicy mPolicy; // 実装は PhoneWindowManager クラス
public void onInitReady() {
// @ 重点分析 initPolicy 関数
initPolicy();
... 省略部分
}
private void initPolicy() {
UiThread.getHandler().runWithScissors(new Runnable() {
@Override
public void run() {
WindowManagerPolicyThread.set(Thread.currentThread(), Looper.myLooper());
mPolicy.init(mContext, WindowManagerService.this, WindowManagerService.this);
}
}, 0);
}
}
// ---------------------------------------------
// WindowManagerPolicy.java
public interface WindowManagerPolicy extends WindowManagerPolicyConstants {
... 省略部分
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs);
// ----------------------------------------------
// PhoneWindowManager.java
public class PhoneWindowManager implements WindowManagerPolicy {
... 省略部分
private class PolicyHandler extends Handler {
... 省略部分
}
public void init(Context context, IWindowManager windowManager,
WindowManagerFuncs windowManagerFuncs) {
// 省略部分…後で紹介
mHandler = new PolicyHandler(); // この Handler は UiThread の Looper を使用します
}
}
WMS#displayReady
- 表示の準備#
ウィンドウアニメーターの初期化が完了したことを示します。
設定を再構成し、DisplayWindowSettings 設定が正常に使用されていることを保証します。
ActivityTaskManager を介して設定を更新します。
// WindowManagerService.java
WindowManagerPolicy mPolicy;
final WindowAnimator mAnimator;
// WMS の構築時に初期化されます
RootWindowContainer mRoot;
public void displayReady() {
synchronized (mGlobalLock) { // ActivityTaskManagerService 内のオブジェクト
if (mMaxUiWidth > 0) {
mRoot.forAllDisplays(displayContent -> displayContent.setMaxUiWidth(mMaxUiWidth));
}
applyForcedPropertiesForDefaultDisplay();
// 1. 初期化完了を示します
mAnimator.ready();
mDisplayReady = true;
// すべての表示を再構成して、強制プロパティと
// DisplayWindowSettings が適用されていることを確認します。
// 2. 設定を再構成し、DisplayWindowSettings 設定が正常に使用されていることを保証します
mRoot.forAllDisplays(DisplayContent::reconfigureDisplayLocked);
// ハードウェアがタッチスクリーンかどうか
mIsTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TOUCHSCREEN);
// ハードウェアが偽のタッチスクリーンかどうか
mIsFakeTouchDevice = mContext.getPackageManager().hasSystemFeature(
PackageManager.FEATURE_FAKETOUCH);
}
try {
// 3. ActivityTaskManager を介して設定を更新します
mActivityTaskManager.updateConfiguration(null);
} catch (RemoteException e) {
}
}
WMS#systemReady
- サービス準備完了#
// WindowManagerService.java
public void systemReady() {
mSystemReady = true;
mPolicy.systemReady();
mRoot.forAllDisplayPolicies(DisplayPolicy::systemReady);
mTaskSnapshotController.systemReady();
mHasWideColorGamutSupport = queryWideColorGamutSupport();
mHasHdrSupport = queryHdrSupport();
mPrimaryDisplayOrientation = queryPrimaryDisplayOrientation();
mPrimaryDisplayPhysicalAddress =
DisplayAddress.fromPhysicalDisplayId(SurfaceControl.getPrimaryPhysicalDisplayId());
UiThread.getHandler().post(mSettingsObserver::loadSettings);
IVrManager vrManager = IVrManager.Stub.asInterface(
ServiceManager.getService(Context.VR_SERVICE));
if (vrManager != null) {
try {
final boolean vrModeEnabled = vrManager.getVrModeState();
synchronized (mGlobalLock) {
vrManager.registerListener(mVrStateCallbacks);
if (vrModeEnabled) {
mVrModeEnabled = vrModeEnabled;
mVrStateCallbacks.onVrStateChanged(vrModeEnabled);
}
}
} catch (RemoteException e) {
// 無視します。VR モードリスナーの登録に失敗した場合、何もできません。
}
}
}
WMS のポイント#
ウィンドウ属性 - レイヤータイプ#
Android は複数のウィンドウをサポートし、ウィンドウを 3 つのカテゴリに分け、WindowManager#LayoutParams に定義されています。
アプリケーションウィンドウ:通常のアプリケーションは以下のウィンドウタイプを使用します(いくつかの例を挙げます)、範囲は 1 ~ 99 の間です。
値 | 名称 | 説明 |
---|---|---|
1 | FIRST_APPLICATION_WINDOW | アプリケーションウィンドウの開始値 |
1 | TYPE_BASE_APPLICATION | 他のアプリがこのウィンドウの上に重なることができる |
2 | TYPE_APPLICATION | 一般的なアプリウィンドウ |
3 | TYPE_APPLICATION_STARTING | アプリケーション起動前の画面(特定の画面を読み込む前) |
4 | TYPE_DRAWN_APPLICATION | 描画が完了するまで待機 |
99 | LAST_APPLICATION_WINDOW | アプリウィンドウの終了値 |
サブウィンドウ:アプリケーションの上に追加されるウィンドウで、一般に サブウィンドウ と呼ばれ、その値の範囲は 1000 ~ 1999 の間です。
値 | 名称 | 説明 |
---|---|---|
1000 | FIRST_SUB_WINDOW | サブウィンドウの開始値 |
1000 | TYPE_APPLICATION_PANEL | このサブウィンドウは依存するアプリの上に表示される |
1001 | TYPE_APPLICATION_MEDIA | ビデオに関連するサブウィンドウを表示 |
1002 | TYPE_APPLICATION_SUB_PANEL | アプリの上に表示され、他のサブウィンドウの上にも表示 |
1003 | TYPE_APPLICATION_ATTACHED_DIALOG | ダイアログタイプのウィンドウ |
1004 | TYPE_APPLICATION_MEDIA_OVERLAY | TYPE_APPLICATION_MEDIA と下のアプリウィンドウの間に表示 |
1005 | TYPE_APPLICATION_ABOVE_SUB_PANEL | TYPE_APPLICATION_SUB_PANEL よりも上のウィンドウ |
1999 | LAST_SUB_WINDOW | サブウィンドウの終了値 |
システムウィンドウ:システムが使用するウィンドウ(以下にいくつかの例を示します)、範囲は 2000 ~ 2999 の間です。
値 | 名称 | 説明 |
---|---|---|
2000 | FIRST_SYSTEM_WINDOW | システムウィンドウの開始値 |
2001 | TYPE_STATUS_BAR | ステータスバーのウィンドウ |
2002 | TYPE_SEARCH_BAR | 検索バーのウィンドウ |
2038 | TYPE_APPLICATION_OVERLAY | 他のアクティビティウィンドウの上に表示 |
2999 | LAST_SYSTEM_WINDOW | システムウィンドウの終了値 |
WindowState の初期化 - ベースレイヤーの決定#
WindowState のコンストラクタから、ベースレイヤーの値は WindowManagerPolicy#getWindowLayerLw
メソッドから取得できます。
// WindowManagerPolicyConstants.java
// 複数のウィンドウ(同じレイヤー)用に予約
int TYPE_LAYER_MULTIPLIER = 10000;
// 複数のウィンドウ(同じレイヤー)の Z 軸オフセット
int TYPE_LAYER_OFFSET = 1000
// ---------------------------------------------------------------
// WindowState.java
final WindowManagerPolicy mPolicy;
WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
WindowState parentWindow, int appOp, WindowManager.LayoutParams a,
... 省略部分の引数) {
// `WindowManager.LayoutParams` をコピー
mAttrs.copyFrom(a);
...
mPolicy = mWmService.mPolicy;
...
// 現在のウィンドウがサブウィンドウかどうかを判断
if (mAttrs.type >= FIRST_SUB_WINDOW && mAttrs.type <= LAST_SUB_WINDOW) {
// 同じレイヤーの複数のウィンドウ用にスペースを予約
// @ getWindowLayerLw メソッドを確認
mBaseLayer = mPolicy.getWindowLayerLw(parentWindow) // 1.
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET; // 2.
// サブウィンドウ
mSubLayer = mPolicy.getSubWindowLayerFromTypeLw(a.type);
...
} else {
// @ getWindowLayerLw メソッドを確認
mBaseLayer = mPolicy.getWindowLayerLw(this)
* TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
mSubLayer = 0;
...
}
}
WindowManagerPolicy は渡された WindowState
を通じてウィンドウの基本レイヤーのレベルを決定します(数値が高いほど、ユーザーに近く、上層になります)。
// WindowManagerPolicy.java
default int getWindowLayerLw(WindowState win) {
return getWindowLayerFromTypeLw(win.getBaseType(), win.canAddInternalSystemWindow());
}
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow) {
return getWindowLayerFromTypeLw(type, canAddInternalSystemWindow,
false /* roundedCornerOverlay */);
}
default int getWindowLayerFromTypeLw(int type, boolean canAddInternalSystemWindow,
boolean roundedCornerOverlay) {
// 常に丸みのあるコーナーレイヤーを最上位に配置します。
if (roundedCornerOverlay && canAddInternalSystemWindow) {
return getMaxWindowLayer();
}
// 1 ~ 99 の間
if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
return APPLICATION_LAYER; // APPLICATION_LAYER は 2
}
switch (type) {
case TYPE_WALLPAPER:
// 壁紙は一番下にありますが、ウィンドウマネージャーがそれを移動させることがあります。
return 1;
case TYPE_PRESENTATION:
case TYPE_PRIVATE_PRESENTATION:
case TYPE_DOCK_DIVIDER:
case TYPE_QS_DIALOG:
case TYPE_PHONE:
return 3;
case TYPE_SEARCH_BAR:
return 4;
case TYPE_INPUT_CONSUMER:
return 5;
case TYPE_SYSTEM_DIALOG:
return 6;
case TYPE_TOAST:
// トーストと接続されたバッテリーのもの
return 7;
case TYPE_PRIORITY_PHONE:
// SIM エラーとロック解除。これが本当に高いレイヤーにあるべきかは不明です。
return 8;
case TYPE_SYSTEM_ALERT:
// ANR / アプリがクラッシュしたダイアログのようなもの
// タイプは非システムアプリには非推奨です。システムアプリの場合、このタイプは
// TYPE_APPLICATION_OVERLAY よりも高いレイヤーにあるべきです。
return canAddInternalSystemWindow ? 12 : 9;
case TYPE_APPLICATION_OVERLAY:
return 11;
case TYPE_INPUT_METHOD:
// 画面上のキーボードやその他の入力メソッドユーザーインターフェースがここに入ります。
return 13;
case TYPE_INPUT_METHOD_DIALOG:
// 画面上のキーボードやその他の入力メソッドユーザーインターフェースがここに入ります。
return 14;
case TYPE_STATUS_BAR:
return 15;
... 省略部分の case
default:
Slog.e("WindowManager", "Unknown window type: " + type);
return 3;
}
}
渡された WindowState
を通じてウィンドウの基本レイヤーのレベルを決定します(数値が高いほど、ユーザーに近く、上層になります)。
WindowManagerPolicy#getSubWindowLayerFromTypeLw
メソッド:親ウィンドウ内のサブウィンドウのオフセットを決定します。
// WindowManagerPolicy.java
default int getSubWindowLayerFromTypeLw(int type) {
switch (type) {
case TYPE_APPLICATION_PANEL:
case TYPE_APPLICATION_ATTACHED_DIALOG:
return APPLICATION_PANEL_SUBLAYER; // 1
case TYPE_APPLICATION_MEDIA:
return APPLICATION_MEDIA_SUBLAYER; // -2
case TYPE_APPLICATION_MEDIA_OVERLAY:
return APPLICATION_MEDIA_OVERLAY_SUBLAYER; // -1
case TYPE_APPLICATION_SUB_PANEL:
return APPLICATION_SUB_PANEL_SUBLAYER; // 2
case TYPE_APPLICATION_ABOVE_SUB_PANEL:
return APPLICATION_ABOVE_SUB_PANEL_SUBLAYER; // 3
}
Slog.e("WindowManager", "Unknown sub-window type: " + type);
return 0;
}
ウィンドウ属性 - LayoutParams#
ウィンドウの統一属性設定は WindowManager#LayoutParams にあり、type
と Flags
の 2 つの設定に分かれています。
タイプ:上記で述べたように、主に アプリケーションウィンドウ
、サブウィンドウ
、システムウィンドウ
の 3 つに分かれています。
フラグ:0 ではなく、以下にいくつかを示します(多くのものがあります)。
値 | フラグ | 説明 |
---|---|---|
0x00000001 | FLAG_ALLOW_LOCK_WHILE_SCREEN_ON | このウィンドウが表示されている限り、画面をロックすることを許可します(FLAG_KEEP_SCREEN_ON と併用可能) |
0x00000002 | FLAG_DIM_BEHIND | ウィンドウの背後のウィンドウが薄くなります |
0x00000004 | FLAG_BLUR_BEHIND | ウィンドウの背後のウィンドウがぼやけます |
0x00000008 | FLAG_NOT_FOCUSABLE | このウィンドウはイベントを受け付けず、イベントは直接後方のウィンドウに渡されます |
0x00000010 | FLAG_NOT_TOUCHABLE | このウィンドウはイベントを受け付けません |
0x00000080 | FLAG_KEEP_SCREEN_ON | このウィンドウが表示されている限り、画面を点灯させ続けます |
システム UI の制御:システム UI の設定は View に定義され、各 View に個別に設定されます。
値 | フラグ | 説明 |
---|---|---|
0 | SYSTEM_UI_FLAG_VISIBLE | システム UI を表示する設定 |
0x00000002 | SYSTEM_UI_FLAG_HIDE_NAVIGATION | ナビゲーションバーを表示しない設定 |
0x00000004 | SYSTEM_UI_FLAG_FULLSCREEN | フルスクリーン |
0x00000100 | SYSTEM_UI_FLAG_LAYOUT_STABLE | UI レイアウトの安定性をできるだけ保持する |
0x00000400 | SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | スクリーン(0,0)から描画を開始し、ステータスバーから描画を開始します |
WindowManagerService は、このデバイスのすべてのウィンドウの上下関係(z 軸の管理)を管理し、描画タスクを下層に伝達します。
変数 | 説明 | 補足 |
---|---|---|
mPolicy : WindowManagerPolicy | ウィンドウポリシーが遵守すべき 一般的な規範 を定義し、WindowManager 特有の UI 動作を提供します | WindowManager はインターフェースであり、その実装は PhoneWindowManager です |
mSessions : ArraySet | 主にプロセス通信に使用され、他のアプリプロセスの View が WMS と通信するには、Session を介して通信する必要があります | 各アプリケーションは WindowManagerGlobal から Session を取得します |
mWindowMap : WindowHashMap | WindowHashMap は HashMap を継承し、すべての ViewImpl を保存するために使用されます;キー: IBinder、値: WindowState | キーは実際には IWindow(ViewRootImpl の内部クラス W)、値はウィンドウ情報を保存します |
mFinishedStarting : ArrayList | AppWindowToken の親クラスは WindowToken であり、アプリが WMS に新しいウィンドウを要求する際にこのトークンを提供し、WMS が検証します | 各 Activity は 1 つの AppWindowToken に対応し、1 つの AppWindowToken が複数の WindowToken ウィンドウを管理します |
mResizingWindows : ArrayList | サイズ変更中のウィンドウを保存するために使用されます | |
mAnimator : WindowAnimator | ウィンドウアニメーションとエフェクトを管理します | |
mH : H | H は Handler タイプで、DisplayThread Looper に属します | WMS にメッセージを送信します |
mInputManager : InputManagerService | IMS システムサービスで、ユーザーが入力メッセージを持つとき、WMS は適切なウィンドウを提供します |