マルチ ウィンドウのサポート

マルチ ウィンドウ モードでは、複数のアプリで同じ画面を同時に共有できます。 アプリを横並びまたは上下に並べて表示する(分割画面モード)、1 つのアプリを小さなウィンドウに重ねて他のアプリに重ねる(ピクチャー イン ピクチャー モード)、または個々のアプリを移動やサイズ変更が可能な個別のウィンドウ(フリーフォーム モード)に表示することができます。

図 1. 分割画面モードで 2 つのアプリを並べて表示します。

ユーザー エクスペリエンスは、Android のバージョンとデバイスの種類によって異なります。

  • Android 7.0(API レベル 24)では、小画面のデバイスでは分割画面モードが導入され、一部のデバイスではピクチャー イン ピクチャー モードが導入されました。

    • 分割画面モードでは、画面全体に 2 つのアプリが左右または上下に並んで表示されます。ユーザーは、2 つのアプリを分離する分割線をドラッグして、一方のアプリを拡大し、もう一方を小さくすることができます。

    • ピクチャー イン ピクチャー モードでは、別のアプリを操作しながら動画の再生を続行できます(ピクチャー イン ピクチャーのサポートをご覧ください)。

    • 大画面デバイスのメーカーは、ユーザーが各アクティビティを自由にサイズ変更できる自由形式モードを有効にできます。

    アクティビティの最小許容ディメンションを指定することで、アプリでのマルチウィンドウ モードの処理方法を構成できます。また、resizeabableActivity="false" を設定して、アプリが常に全画面表示されるようにすることで、アプリのマルチウィンドウ モードを無効にすることもできます。

  • Android 8.0(API レベル 26)では、ピクチャー イン ピクチャー モードが小画面のデバイスに拡張されています。

  • Android 12(API レベル 31)では、マルチウィンドウ モードが標準の動作になります。

    • 大画面(最小幅 600 dp 以上)では、アプリの構成に関係なく、プラットフォームはマルチウィンドウ モードのすべてのアプリをサポートします。resizeableActivity="false" の場合、ディスプレイの寸法に合わせるために必要なとき、アプリは互換モードになります。

    • 小画面の場合(最小幅が 600 dp 未満の場合)、システムはアクティビティの minWidthminHeight をチェックして、マルチウィンドウ モードで実行できるかどうかを判断します。resizeableActivity="false" の場合、最小の幅と高さに関係なく、アプリはマルチウィンドウ モードで実行できなくなります。

分割画面モード

ユーザーは次の操作を行うことで、分割画面モードを有効にできます。

  1. 履歴画面を開きます。
  2. スワイプしてアプリをビューに表示します。
  3. アプリのタイトルバーにあるアプリアイコンをタップします。
  4. [分割画面] メニュー オプションを選択します。
  5. 履歴画面から別のアプリを選択するか、履歴画面を閉じて別のアプリを実行する

ユーザーは、ウィンドウ分割線を画面の上下左右いずれかの端までドラッグすることで、分割画面モードを終了できます。

隣接するデバイスを発射

アプリがインテントを介してコンテンツにアクセスする必要がある場合は、FLAG_ACTIVITY_LAUNCH_ADJACENT を使用して、隣接する分割画面のウィンドウでコンテンツを開くことができます。

FLAG_ACTIVITY_LAUNCH_ADJACENT は Android 7.0(API レベル 24)で導入され、分割画面モードで実行されているアプリが隣接するウィンドウでアクティビティを起動できるようにしました。

Android 12L(API レベル 32)以降では、このフラグの定義が拡張され、全画面を実行しているアプリが分割画面モードを有効にして、隣接するウィンドウでアクティビティを起動できるようになりました。

隣接するアクティビティを起動するには、FLAG_ACTIVITY_LAUNCH_ADJACENTFLAG_ACTIVITY_NEW_TASK と組み合わせて使用します。次に例を示します。

Kotlin

fun openUrlInAdjacentWindow(url: String) {
    Intent(Intent.ACTION_VIEW).apply {
        data = Uri.parse(url)
        addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT or
                           Intent.FLAG_ACTIVITY_NEW_TASK)
    }.also { intent ->
        startActivity(intent)
    }
}

Java

public void openUrlInAdjacentWindow(String url) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(Uri.parse(url));
    intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}

マルチ ウィンドウ モードでのアクティビティのライフサイクル

マルチウィンドウ モードは、アクティビティのライフサイクルを変更しません。ただし、複数のウィンドウでアプリの再開状態は、Android のバージョンによって異なります。

複数のアプリの再開

Android 10(API レベル 29)以降のバージョンでは、複数のアプリの再開がサポートされています。デバイスがマルチウィンドウ モードのとき、すべてのアクティビティは RESUMED 状態のままになります。透明なアクティビティがアクティビティの上に重ねられている場合や、アクティビティがフォーカス可能でない場合(アクティビティがピクチャー イン ピクチャー モードになっている場合など)、アクティビティは一時停止できます。また、通知ドロワーが開いている場合など、特定の時間にアクティビティがフォーカスされていない可能性もあります。onStop() メソッドは通常どおりに動作します。このメソッドは、アクティビティが画面から取り除かれるたびに呼び出されます。

複数のアプリの再開は、Android 9(API レベル 28)を搭載した一部のデバイスでも利用できます。Android 9 デバイスで複数のアプリの再開を有効にするには、以下のマニフェスト メタデータを追加します。

<meta-data android:name="android.allow_multiple_resumed_activities" android:value="true" />

デバイスがこのマニフェスト メタデータをサポートしているかどうかを確認するには、デバイスの仕様をご覧ください。

Android 9

Android 9(API レベル 28)以前のマルチウィンドウ モードでは、ある時点でアクティブなのは、ユーザーが最後に操作したアクティビティのみです。このアクティビティは最上位とみなされ、RESUMED 状態の唯一のアクティビティになります。その他の表示アクティビティはすべて STARTED ですが、RESUMED ではありません。ただし、システムは、表示されているが再開されていないアクティビティに、表示されていないアクティビティよりも高い優先度を割り当てます。表示されたアクティビティのいずれかをユーザーが操作すると、そのアクティビティが再開され、それまでの最上位のアクティビティは STARTED 状態になります。

1 つのアクティブ アプリ プロセス内に複数のアクティビティがある場合、Z オーダーが最も高いアクティビティが再開され、他のアクティビティは一時停止されます。

構成の変更

ユーザーがアプリをマルチウィンドウ モードに切り替えると、構成の変更を処理するで指定されているように、システムはアクティビティに構成の変更を通知します。これは、ユーザーがアプリのサイズを変更するか、アプリを全画面モードに戻した場合にも発生します。

基本的に、この変更は、デバイスが縦向きから横向きに切り替わったことをシステムがアプリに通知する場合と同じアクティビティ ライフサイクルに影響します。ただし、アプリのディメンションは単に入れ替えられるだけでなく変更されます。アクティビティ自体が構成の変更を処理することも、アプリ側でアクティビティを破棄して新しいディメンションで再作成することもできます。

ユーザーがウィンドウのサイズを変更して、高さまたは幅を拡大した場合、システムはユーザー操作に合わせてアクティビティのサイズを変更し、必要に応じて構成の変更を実行します。新たに公開された領域にアプリが描画処理が遅れた場合、システムはその領域を windowBackground 属性またはデフォルトの windowBackgroundFallback スタイル属性で指定された色で一時的に塗りつぶします。

リソースへの排他的アクセス

複数のアプリの再開機能をサポートするには、onTopResumedActivityChanged() ライフサイクル コールバックを使用します。

このコールバックは、アクティビティが一番上の再開位置を取得または失ったときに呼び出されます。これは、アクティビティがマイクやカメラなどの共有シングルトン リソースを使用する場合に重要です。

Kotlin

override fun onTopResumedActivityChanged(topResumed: Boolean) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

Java

@Override
public void onTopResumedActivityChanged(boolean topResumed) {
    if (topResumed) {
        // Top resumed activity
        // Can be a signal to re-acquire exclusive resources
    } else {
        // No longer the top resumed activity
    }
}

アプリはその他の理由(共有ハードウェアの取り外しなど)でリソースを失うこともあります。

いずれにしても、アプリは使用可能なリソースに影響するイベントと状態変化にスムーズに対処する必要があります。

カメラを使用するアプリの場合、CameraManager.AvailabilityCallback#onCameraAccessPrioritiesChanged() は、カメラへのアクセスを試みるのが適切なタイミングである可能性があるというヒントを提供します。このメソッドは、Android 10(API レベル 29)以降で使用できます。

resizeableActivity=false はカメラへの排他的アクセスを保証するものではありません。カメラを使用する他のアプリを他のディスプレイで開くことができるためです。

図 2. マルチ ウィンドウ モードのカメラ。

アプリがフォーカスを喪失したときにカメラを解放する必要はありません。たとえば、新たにフォーカスされた最上位で再開されたアプリをユーザーが操作している間、カメラ プレビューを続行できます。最上位で再開されたアプリではない場合でも、アプリはカメラを実行し続けることができますが、接続解除のケースを適切に処理する必要があります。最上位に再開されたアプリがカメラを使用する必要がある場合は、カメラを起動でき、アプリはアクセスを失います。アプリがフォーカスを戻したら、カメラを再度開くことができます。

アプリが CameraDevice.StateCallback#onDisconnected() コールバックを受け取ると、その後にカメラデバイスで呼び出されると、CameraAccessException がスローされます。

マルチディスプレイ

Android 10(API レベル 29)は、セカンダリ ディスプレイ上のアクティビティをサポートしています。アクティビティが複数のディスプレイを持つデバイスで実行されている場合、ユーザーはディスプレイ間でアクティビティを移動できます。複数のアプリの再開は、マルチスクリーンのシナリオにも適用されます。複数のアクティビティを同時にユーザー入力を受け取ることができます。

アプリは、起動時や別のアクティビティの作成時に、どのディスプレイで実行するかを指定できます。この動作は、マニフェスト ファイルで定義したアクティビティの起動モード、またはアクティビティを起動するエンティティが設定したインテント フラグやオプションによって異なります。詳細については、ActivityOptions クラスをご覧ください。

アクティビティをセカンダリ ディスプレイに移動すると、コンテキストの更新、ウィンドウのサイズ変更、構成とリソースの変更が行われることがあります。アクティビティが構成の変更を処理した場合は、onConfigurationChanged() で通知されます。処理できない場合は、アクティビティが再起動されます。

構成の変更を処理する場合、アクティビティは onCreate()onConfigurationChanged() で現在のディスプレイを確認する必要があります。ディスプレイが変更されたときは、リソースとレイアウトを必ず更新するようにします。

アクティビティに対して選択した起動モードで複数のインスタンスが許可されている場合、セカンダリ画面で起動することで、アクティビティの新しいインスタンスを作成できます。両方のアクティビティは同時に再開されます。

図 3. 複数のディスプレイに表示されたアクティビティの複数のインスタンス

また、Android 8.0 で導入されたマルチディスプレイ API もご覧ください。

アクティビティとアプリのコンテキスト

マルチディスプレイでは適切なコンテキストを使用することが非常に重要です。リソースにアクセスするときのアクティビティ コンテキスト(表示される)は、アプリ コンテキスト(表示されない)とは異なります。

アクティビティ コンテキストはディスプレイに関する情報を含んでおり、アクティビティの表示領域に合わせて常に調整されます。これにより、アプリのディスプレイ密度やウィンドウ指標に関する正しい情報を取得できます。現在のウィンドウやディスプレイに関する情報を取得するには、常にアクティビティ コンテキスト(または別の UI ベースのコンテキスト)を使用する必要があります。これは、コンテキストの情報を使用する一部のシステム API にも影響します(たとえば、トーストの概要をご覧ください)。

リソースとコンテキストは、アクティビティのウィンドウ構成と親ディスプレイによって定義されます。現在のディスプレイは次のように取得します。

Kotlin

val activityDisplay = activity.getDisplay()

Java

Display activityDisplay = activity.getDisplay();

現在のアクティビティのウィンドウ指標は次のように取得します。

Kotlin

val windowMetrics = activity.getWindowManager().getCurrentWindowMetrics()

Java

WindowMetrics windowMetrics = activity.getWindowManager().getCurrentWindowMetrics();

現在のシステム構成の最大ウィンドウ指標は次のように取得します。

Kotlin

val maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics()

Java

WindowMetrics maximumWindowMetrics = activity.getWindowManager().getMaximumWindowMetrics();

最大ウィンドウ指標は、計算、レイアウトの選択、事前に取得するリソースのサイズの決定に役立ちます。これを onCreate() で利用できるようにすると、最初のレイアウトパスの前にこれらの決定を行うことができます。これらの指標は、特定のビュー要素のレイアウトには使用しないでください。代わりに、Configuration オブジェクトの情報を使用してください。

ディスプレイ カットアウト

折りたたみ式デバイスでは、折りたたんだときや広げたときにカットアウト ジオメトリが変更されることがあります。カットアウトの問題を回避するには、ディスプレイ カットアウトをサポートするをご覧ください。

セカンダリ ディスプレイ

使用可能なディスプレイは、DisplayManager システム サービスから取得できます。

Kotlin

val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = displayManager.getDisplays()

Java

DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display[] displays = displayManager.getDisplays();

ディスプレイ サイズや、ディスプレイが安全かどうかを示すフラグなど、特定のディスプレイに関する情報を取得するには、Display クラスを使用します。ただし、表示サイズがアプリに割り当てられた表示領域と同じになるとは限りません。マルチウィンドウ モードでは、アプリはディスプレイの一部を占有します。

アクティビティをディスプレイ上で起動できるかどうかは、次のようにして判断します。

Kotlin

val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)

Java

ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
boolean activityAllowed = activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent);

その後、次のようにしてディスプレイ上でアクティビティを起動します。

Kotlin

val options = ActivityOptions.makeBasic()
options.setLaunchDisplayId(targetDisplay.displayId)
startActivity(intent, options.toBundle())

Java

ActivityOptions options = ActivityOptions.makeBasic();
options.setLaunchDisplayId(targetDisplay.displayId);
startActivity(intent, options.toBundle());

マルチディスプレイのサポート

Android は、ソフトウェア キーボード、壁紙、ランチャーをマルチディスプレイでサポートしています。

ソフトウェア キーボード

ディスプレイがシステム デコレーションをサポートするように設定されている場合は、キーボードをセカンダリ画面上に表示できます。そのディスプレイでテキスト フィールドへの入力をリクエストすると、インプット メソッド エディタが自動的に表示されます。

図 4. セカンダリ ディスプレイのキーボード。

壁紙

Android 10(API レベル 29)では、セカンダリ画面に壁紙を設定できます。フレームワークは、ディスプレイごとに WallpaperService.Engine の個別のインスタンスを作成します。各エンジンのサーフェスが個別に描画されるようにします。デベロッパーは、WallpaperService.Engine#getDisplayContext() の表示コンテキストを使用してアセットを読み込むことができます。また、WallpaperInfo.xml ファイルで android:supportsMultipleDisplays="true" が設定されていることを確認します。

図 5. スマートフォンとセカンダリ ディスプレイに表示された壁紙

ランチャー

新しいインテント フィルタ カテゴリ SECONDARY_HOME は、セカンダリ画面専用のアクティビティを提供します。このアクティビティのインスタンスは、システム デコレーションをサポートするすべてのディスプレイで使用されます(ディスプレイごとに 1 つ)。

<activity>
    ...
    <intent-filter>
        <category android:name="android.intent.category.SECONDARY_HOME" />
        ...
    </intent-filter>
</activity>

アクティビティには、複数のインスタンスの作成を妨げず、さまざまな画面サイズに適応可能な起動モードを設定する必要があります。起動モードを singleInstance または singleTask に設定することはできません。

たとえば、Launcher3 の AOSP 実装は SECONDARY_HOME アクティビティをサポートしています。

図 6. スマートフォンのマテリアル デザイン ランチャー
図 7.セカンダリ ディスプレイのマテリアル デザイン ランチャー

ウィンドウ指標

Android 11(API レベル 30)では、マルチウィンドウ モードで実行されるアプリの境界を提供するため、次の WindowManager メソッドが導入されました。

Jetpack WindowManager ライブラリのメソッド computeCurrentWindowMetrics()computeMaximumWindowMetrics() はそれぞれ同様の機能を備えていますが、API レベル 14 との下位互換性があります。

現在のディスプレイ以外のディスプレイの指標を取得するには、次の操作を行います(コード スニペットを参照)。

  • ディスプレイ コンテキストを作成する
  • ディスプレイのウィンドウ コンテキストを作成する
  • ウィンドウ コンテキストの WindowManager を取得する
  • アプリで使用できる最大ディスプレイ領域の WindowMetrics を取得する

Kotlin

val windowMetrics = context.createDisplayContext(display)
                    .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                    .getSystemService(WindowManager::class.java)
                    .maximumWindowMetrics

Java

WindowMetrics windowMetrics = context.createDisplayContext(display)
                              .createWindowContext(WindowManager.LayoutParams.TYPE_APPLICATION, null)
                              .getSystemService(WindowManager.class)
                              .getMaximumWindowMetrics();

サポート終了のメソッド

Display メソッドの getSize()getMetrics() は API レベル 30 でサポートが終了し、新しい WindowManager メソッドに置き換えられました。

Android 12(API レベル 31)では、Display メソッドの getRealSize()getRealMetrics() のサポートが廃止され、getMaximumWindowMetrics() の動作により近い動作になるよう動作が更新されています。

マルチ ウィンドウ モードの設定

アプリが Android 7.0(API レベル 24)以降をターゲットとしている場合は、アプリのアクティビティがマルチウィンドウ モードをサポートする方法と、それをサポートするかどうかを設定できます。マニフェスト内で属性を設定して、サイズとレイアウトの両方を制御できます。ルート アクティビティの属性設定は、タスクスタック内のすべてのアクティビティに適用されます。たとえば、ルート アクティビティに android:resizeableActivity="true" が設定されている場合、タスクスタック内のすべてのアクティビティはサイズ変更可能です。Chromebook などの一部の大型デバイスでは、android:resizeableActivity="false" を指定しても、サイズ変更可能なウィンドウでアプリが実行されることがあります。これによってアプリが動作しなくなった場合は、Google Play のフィルタを使用して、そのようなデバイスでのアプリの利用を制限できます。

Android 12(API レベル 31)では、デフォルトでマルチ ウィンドウ モードになっています。大画面(画面幅 600 dp 以上)では、アプリの構成に関係なく、すべてのアプリがマルチウィンドウ モードで実行されます。小さい画面の場合、システムはアクティビティの minWidthminHeightresizeableActivity の設定をチェックし、アクティビティをマルチウィンドウ モードで実行できるかどうかを判断します。

resizeableActivity

API レベル 30 以前でマルチウィンドウ モードを有効または無効にするには、マニフェストの <activity> 要素または <application> 要素でこの属性を設定します。

<application
  android:name=".MyActivity"
  android:resizeableActivity=["true" | "false"] />;

この属性を true に設定すると、アクティビティは分割画面モードと自由形式モードで起動できます。この属性が false に設定されている場合、アクティビティはマルチウィンドウ モードをサポートしません。この値が false の場合、ユーザーがマルチウィンドウ モードでアクティビティを起動しようとすると、アクティビティが全画面表示されます。

API レベル 24 以降をターゲットとしているアプリで、この属性に値を指定しなかった場合、属性の値はデフォルトで true になります。

API レベル 31 以降をターゲットとしているアプリの場合、この属性による動作は小画面と大画面で異なります。

  • 大画面(画面幅 600 dp 以上): すべてのアプリでマルチウィンドウ モードがサポートされます。この属性は、アクティビティのサイズが変更可能かどうかを示します。resizeableActivity="false" の場合、ディスプレイの寸法に合わせるために必要なとき、アプリは互換モードになります。
  • 小画面(画面幅 600 dp 未満): resizeableActivity="true" で、アクティビティの最小幅と最小高さがマルチウィンドウ要件の範囲内である場合、アクティビティはマルチウィンドウ モードをサポートします。resizeableActivity="false" の場合、アクティビティの最小幅と高さに関係なく、アクティビティはマルチウィンドウ モードをサポートしません。

supportsPictureInPicture

マニフェストの <activity> ノードでこの属性を設定して、アクティビティがピクチャー イン ピクチャー モードをサポートするかどうかを指定します。

<activity
  android:name=".MyActivity"
  android:supportsPictureInPicture=["true" | "false"] />

configChanges

ユーザーがウィンドウのサイズを変更したときなど、マルチウィンドウ構成の変更を自身で処理するには、android:configChanges 属性をアプリ マニフェストの <activity> ノードに追加し、少なくとも次の値を指定します。

<activity
  android:name=".MyActivity"
  android:configChanges="screenSize | smallestScreenSize
      | screenLayout | orientation" />

android:configChanges を追加すると、アクティビティとフラグメントは破棄されて再作成されるのではなく、onConfigurationChanged() へのコールバックを受け取ります。その後、ビューを手動で更新したり、リソースを再読み込みしたり、必要に応じて他のオペレーションを実行したりできます。

<layout>

Android 7.0(API レベル 24)以降では、<layout> マニフェスト要素は、マルチウィンドウ モードでのアクティビティの動作に影響する複数の属性をサポートしています。

  • android:defaultHeightandroid:defaultWidth: 自由形式モードで起動されたときのアクティビティのデフォルトの高さと幅。

  • android:gravity: フリーフォーム モードで起動されたときのアクティビティの初期配置。適切な値については、Gravity クラスをご覧ください。

  • android:minHeightandroid:minWidth: 分割画面モードと自由形式モードの両方におけるアクティビティの最小の高さと最小幅。ユーザーが分割画面モードで分割線を移動してアクティビティを指定された最小値よりも小さくすると、システムはユーザーがリクエストしたサイズに合わせてアクティビティを切り取ります。

次のコードは、アクティビティがフリーフォーム モードで表示されるときに、アクティビティのデフォルトのサイズと位置、および最小サイズを指定する方法を示しています。

<activity android:name=".MyActivity">
    <layout android:defaultHeight="500dp"
          android:defaultWidth="600dp"
          android:gravity="top|end|..."
          android:minHeight="450dp"
          android:minWidth="300dp" />
</activity>

ランタイムのマルチウィンドウ モード

Android 7.0 以降、マルチウィンドウ モードで実行できるアプリをサポートする機能がシステムによって提供されます。

マルチウィンドウ モードで無効になる機能

マルチウィンドウ モードでは、Android は、他のアクティビティまたはアプリとデバイスの画面を共有しているアクティビティに適用されない機能を無効にするか、無視することがあります。

また、一部のシステム UI カスタマイズ オプションが無効になります。たとえば、アプリがマルチウィンドウ モードで実行されている場合、ステータスバーを非表示にすることはできません(システム UI の表示設定を制御するをご覧ください)。

android:screenOrientation 属性の変更は無視されます。

マルチ ウィンドウ モードのクエリとコールバック

Activity クラスは、マルチウィンドウ モードをサポートする次のメソッドを提供します。

  • isInMultiWindowMode(): アクティビティがマルチウィンドウ モードにあるかどうかを示します。

  • isInPictureInPictureMode(): アクティビティがピクチャー イン ピクチャー モードかどうかを示します。

  • onMultiWindowModeChanged(): アクティビティがマルチウィンドウ モードになる、またはマルチウィンドウ モードから抜けるたびに、システムがこのメソッドを呼び出します。アクティビティがマルチウィンドウ モードに入った場合は、このメソッドに true 値が渡され、アクティビティがマルチウィンドウ モードから出る場合は false 値が渡されます。

  • onPictureInPictureModeChanged(): アクティビティがピクチャー イン ピクチャー モードになる、またはピクチャー イン ピクチャー モードから抜けるたびに、システムがこのメソッドを呼び出します。アクティビティがピクチャー イン ピクチャー モードに入ると、このメソッドに true 値が渡され、アクティビティがピクチャー イン ピクチャー モードを終了している場合は false 値が渡されます。

Fragment クラスは、これらのメソッドの多くのバージョン(Fragment.onMultiWindowModeChanged() など)を公開しています。

ピクチャー イン ピクチャー モード

アクティビティをピクチャー イン ピクチャー モードにするには、enterPictureInPictureMode() を呼び出します。デバイスがピクチャー イン ピクチャー モードをサポートしていない場合、このメソッドは機能しません。詳しくは、ピクチャー イン ピクチャー(PIP)を使用して動画を追加するをご覧ください。

マルチウィンドウ モードの新しいアクティビティ

新しいアクティビティを起動するときに、可能であれば現在のアクティビティの隣に新しいアクティビティを表示するように指定できます。隣接するウィンドウで新しいアクティビティを作成しようとすることを示すインテント フラグ FLAG_ACTIVITY_LAUNCH_ADJACENT を使用します。これにより、2 つのアクティビティが画面を共有します。システムでは最善を尽くしますが、必ず行われるとは限りません。

デバイスがフリーフォーム モードのときに新しいアクティビティを起動する場合は、ActivityOptions.setLaunchBounds() を呼び出して新しいアクティビティのディメンションと画面の位置を指定できます。デバイスがマルチウィンドウ モードでない場合、このメソッドは機能しません。

API レベル 30 以前では、タスクスタック内でアクティビティを起動すると、画面上のアクティビティがそのアクティビティに置き換わり、マルチウィンドウ プロパティがすべて継承されます。新しいアクティビティをマルチウィンドウ モードで別のウィンドウとして起動する場合は、新しいタスクスタックで起動する必要があります。

Android 12(API レベル 31)では、アプリはタスク ウィンドウを複数のアクティビティに分配できます。XML 構成ファイルを作成するか、Jetpack WindowManager API 呼び出しを行うことで、アプリのアクティビティを全画面表示、横並び、積み重ねて表示する方法を決定します。

ドラッグ&ドロップ

2 つのアクティビティが画面を共有しているとき、ユーザーは一方のアクティビティからもう一方のアクティビティにデータをドラッグ&ドロップできます(Android 7.0 より前のバージョンでは、1 つのアクティビティ内でのみデータをドラッグ&ドロップできました)。ドロップされたコンテンツの受け入れに対するサポートを迅速に追加するには、DropHelper API をご覧ください。ドラッグ&ドロップの包括的なガイダンスについては、ドラッグ&ドロップを有効にするをご覧ください。

マルチインスタンス

各ルート アクティビティは独自のタスクを持ち、独立したプロセスで実行され、独自のウィンドウに表示されます。アプリの新しいインスタンスを別のウィンドウで起動するには、FLAG_ACTIVITY_NEW_TASK フラグを使用して新しいアクティビティを開始します。これをマルチウィンドウ属性の一部と組み合わせて、新しいウィンドウの特定の場所をリクエストできます。たとえば、ショッピング アプリであれば、商品比較のために複数のウィンドウを表示できます。

Android 12(API レベル 31)では、アクティビティの 2 つのインスタンスを同じタスク ウィンドウで並べて起動できます。

ユーザーがアプリ ランチャーまたはタスクバーからアプリの別のインスタンスを起動できるようにするには、ランチャー アクティビティで android:resizeableActivity="true" を設定し、複数インスタンスを禁止する起動モードを使用しないでください。たとえば、FLAG_ACTIVITY_MULTIPLE_TASK または FLAG_ACTIVITY_NEW_DOCUMENT が設定されている場合、singleInstancePerTask アクティビティを異なるタスクで複数回インスタンス化できます。

マルチインスタンスをマルチパネル レイアウト(単一のウィンドウ内で実行される SlidingPaneLayout を使用するリスト詳細プレゼンテーションなど)と混同しないでください。

なお、折りたたみ式デバイスで複数のインスタンスが個別のウィンドウで実行されている場合、形状が変更されると、1 つ以上のインスタンスがバックグラウンドに移動されることがあります。たとえば、デバイスが折りたたまれていない状態で、2 つのアプリ インスタンスが折り目の両側にある 2 つのウィンドウで実行されているとします。デバイスが折りたたまれると、小さくなった画面に合うよう両方のインスタンスが調整される代わりに、片方のインスタンスが終了する可能性があります。

マルチ ウィンドウ モードの確認

アプリが API レベル 24 以降をターゲットとしているかどうかにかかわらず、Android 7.0 以降を搭載したデバイスでユーザーがマルチウィンドウ モードでアプリを起動しようとした場合に備えて、アプリがマルチウィンドウ モードでどのように動作するかを確認する必要があります。

デバイスをテストする

Android 7.0(API レベル 24)以降を搭載したデバイスは、マルチ ウィンドウ モードをサポートしています。

API レベル 23 以下

アプリが固定された画面の向きを宣言していない限り、ユーザーがマルチ ウィンドウ モードでアプリを使用しようとすると、システムはアプリのサイズを強制的に変更します。

アプリが画面の向きの固定を宣言しない場合は、Android 7.0 以降を搭載したデバイスでアプリを起動し、アプリを分割画面モードにしてみる必要があります。アプリが強制的にサイズ変更されたときに、ユーザー エクスペリエンスが許容できることを確認します。

アプリが固定された画面の向きを宣言している場合は、アプリをマルチウィンドウ モードにしてみる必要があります。マルチ ウィンドウ モードにしても、全画面モードのままであることを確認します。

API レベル 24~30

アプリが API レベル 24~30 をターゲットにしており、マルチウィンドウのサポートを無効にしていない場合は、分割画面モードとフリーフォーム モードの両方で次の動作を確認します。

  • アプリを全画面表示で起動してから、[履歴] ボタンを長押ししてマルチウィンドウ モードに切り替えます。アプリが適切に切り替わることを確認します。

  • マルチ ウィンドウ モードでアプリを直接起動し、正しく起動することを確認します。アプリをマルチウィンドウ モードで起動するには、[最近] ボタンを押し、アプリのタイトルバーを長押しして、画面上のハイライト表示された領域のいずれかにドラッグします。

  • 画面の分割線をドラッグして、分割画面モードでアプリのサイズを変更します。アプリがクラッシュせずにサイズ変更され、必要な UI 要素が表示されることを確認します。

  • アプリの最小サイズを指定している場合は、ウィンドウ サイズがそのサイズよりも小さくなるようにアプリのサイズを変更してみます。指定した最小サイズよりも小さくなるようにアプリのサイズを変更できないことを確認します。

  • すべてのテストを通して、アプリのパフォーマンスが許容範囲内かどうかを確認します。たとえば、アプリのサイズ変更後に UI を更新するための遅延が長すぎないことを確認します。

API レベル 31 以降

アプリが API レベル 31 以降をターゲットとしており、メイン アクティビティの最小の幅と最小の高さが、使用可能な表示領域の各サイズ以下の場合は、API レベル 24 ~ 30 に記載されている動作をすべて確認します。

テスト チェックリスト

マルチウィンドウ モードでアプリのパフォーマンスを確認するには、以下の操作を試します。特に記載のない限り、分割画面モードとフリーフォーム モードの両方で試す必要があります。

  • マルチウィンドウ モードを開始して終了します。

  • アプリから別のアプリに切り替えて、表示されているもののアクティブでないときに、アプリが正しく動作することを確認します。たとえば、アプリが動画を再生している場合、ユーザーが別のアプリを操作している間も動画が再生され続けることを確認します。

  • 分割画面モードで、画面の分割線を動かしてアプリのサイズを変更してみてください。これらのオペレーションを、左右に並べて、または上下に置いて試します。アプリがクラッシュせず、基本的な機能が表示され、サイズ変更オペレーションに時間がかかりすぎないことを確認します。

  • いくつかのサイズ変更操作を続けてすばやく行います。アプリのクラッシュやメモリリークが発生していないことを確認します。Android Studio の Memory Profiler は、アプリのメモリ使用量に関する情報を提供します(Memory Profiler を使用してアプリのメモリ使用量を検査するをご覧ください)。

  • さまざまなウィンドウ構成でアプリを正常に使用し、アプリが適切に動作することを確認します。テキストが判読可能で、UI 要素が操作するには小さすぎないことを確認します。

マルチウィンドウのサポートを無効にする場合

API レベル 24 ~ 30 では、android:resizeableActivity="false" を設定してマルチウィンドウ サポートを無効にした場合、Android 7.0 ~ 11 を搭載したデバイスでアプリを起動し、アプリを分割画面モードとフリーフォーム モードにしてみる必要があります。その際、アプリが全画面モードのままであることを確認します。

参考情報

Android でのマルチウィンドウのサポートについて詳しくは、以下をご覧ください。

##

あなたへのおすすめ

* 注: リンクテキストは JavaScript がオフになっている ときに表示されます * デバイス互換性モード * 大画面のサイズ変更をサポートする * 設定の変更を処理する