折りたたみ式端末に対応したアプリの作成

Android 10 (API レベル 29) では、折りたたみ式端末やさまざまな折りたたみパターン向けのサポート機能がさらに追加されています。

折りたたみ端末を広げることによってさらに大きい画面が実現されるなら、ユーザーにとってメリットとなります。

  • 通常、画面が大きくなれば、さらに没入感のあるエクスペリエンスが実現されます。
  • 複数ウィンドウにより、ユーザーは複数のタスクを同時に実行できます。

折りたたんだり広げたりすることで、画面のサイズ、密度、または縦横比が変わる場合があります。Android 開発においてこれは新しい問題ではありません。折りたたみ式でない場合にも、すでに発生しています。

  • スマートフォン: 縦表示モードと横表示モードの切り替え。
  • デスクトップ モードで実行されている Chrome OS: Android アプリのサイズ変更。
  • 複数画面または追加画面のある端末。

このページでは、折りたたみ式フォーム ファクタでアプリが適切に動作するようにするためのベスト プラクティスを説明します。

折りたたみ式サポートが関係する Android 10 の変更の概要もご覧ください。

アプリの続行可能性

折りたたみ式端末上で実行されるアプリは、1 つの画面から別の画面に自動的に移行することがあります。快適なユーザー エクスペリエンスを提供するため、現在のタスクが移行後もシームレスに続行することは非常に重要です。アプリは同じ状態、同じ位置で再開しなければなりません。折りたたみ式端末の折りたたみ方には、内側や外側など、いろいろあることに注意してください。

システムは移行中に構成変更をトリガーするため、アプリでは、UI 状態を保存し、構成変更のサポートを適切な方法で実現する必要があります。

アプリをサイズ変更可能にする

アプリがマルチ ウィンドウ モードで、また動的サイズ変更時に動作するようにしなければなりません。そのためには、resizeableActivity=true を設定します。それにより、アプリが直面するフォーム ファクタや環境が何であれ、最大限の互換性が提供されます(折りたたみ式、デスクトップ モード、フリーフォーム ウィンドウなど)。分割画面や折りたたみ式エミュレータでアプリの動作をテストしてください。

アプリが resizeableActivity=false を設定している場合、マルチ ウィンドウをサポートしないことをプラットフォームに対して伝えることになります。それでもシステムによりアプリのサイズ変更が実行されたり、マルチ ウィンドウ モードになったりすることがありますが、アプリのすべてのコンポーネントに同じ構成を適用することにより、互換性が実現されます(アクティビティやサービスのすべてなどを含む)。場合によっては大きな変更(ディスプレイのサイズの変更など)のために、構成変更ではなくプロセスの再起動が実行される可能性があります。

たとえば、以下のアクティビティでは、maxAspectRatio と共に resizableActivity=false を設定しています。折りたたまれた端末を広げた時点で、アプリを互換性モードにすることにより、アクティビティの構成、サイズ、およびアスペクト比が保たれます。

resizeableActivity を設定しない場合、または true に設定する場合、システムは、そのアプリがマルチ ウィンドウを全面的にサポートしており、サイズ変更可能であると判断します。

OEM によっては、アクティビティの表示域が変更になるたびに画面上に小さな再起動アイコンを追加する機能が実装されている場合があることに注意してください。これによりユーザーには、新しい構成でアクティビティを再起動する機会が与えられます。

新しい画面縦横比

Android 10 (API レベル 29) 以上 では、サポートされるアスペクト比がさら拡大しています。折りたたみ式の場合、フォーム ファクタは超縦長の細長い画面(折りたたみ式端末で 21:9 など)から、1:1 に至るまで変化する可能性があります。

多くの端末で可能な限り互換性を維持するため、できるだけ多くの画面縦横比でアプリのテストを実施するようにしてください。

サポートできない縦横比がある場合は、(以前と同じように)maxAspectRatio、および minAspectRatio を使用することにより、アプリで処理可能な最高および最低の縦横比を指定することができます。それらの限界を超える画面では、アプリが互換性モードになる可能性があります。

下部ナビゲーション ビューに 5 つのアイコンがある場合、Android 10 (API レベル 29) 以上 の実行されている端末は 2 インチの最低タッチ ターゲット サイズが保証されています。互換性定義ドキュメントをご覧ください。

マルチウィンドウ

複数のウィンドウを実行できることは、大画面のメリットの 1 つです。過去において一部の端末では、2 つのアプリを横に並べて表示することが一般的でした。技術は進み、画面上で 3 つ以上のアプリを同時に実行できるようになり、さらにそれらの間でコンテンツを共有できるようにもなりました。

アプリでマルチウィンドウが適切にサポートされていない場合、resizeableActivity=false を設定することができます。詳しくは、マルチウィンドウ ガイドをご覧ください。

マルチウィンドウの普及が進んでいるため、アプリでドラッグ&ドロップの機能をサポートすることを考慮してください。

マルチ再開

Android 9.0 以前が実行されている場合、フォーカスのあったアプリのみが再開状態になっていました。それ以外の表示アクティビティは一時停止状態になります。アプリが停止した時点でリソースをクローズしたりコンテンツ再生を停止したりすると問題となる場合があります。

Android 10 の場合、この動作は変更になりました。端末がマルチウィンドウ モードの場合、すべてのアクティビティが再開状態にとどまります。これはマルチ再開と呼ばれます。最前面に透過アクティビティがある場合、またはアクティビティがフォーカス可能でない場合(ピクチャ イン ピクチャ モードなど)、アクティビティが一時停止することがあることに注意してください。また、タイミングによってはフォーカスのあるアクティビティがない場合があります。たとえば、通知ドロワーが表示されている場合です。OnStop は通常通りに動作します。これは、アクティビティが画面外になった時点で呼び出されます。

マルチ再開は、Android 9.0 が実行されている一部の端末上でも使用可能です。それらの端末上でマルチ再開の機能をオンにするには、以下のマニフェスト メタデータを追加することができます:

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

特定の端末でこのマニフェスト メタデータがサポートされることを確認するには、その端末の仕様を参照してください。

排他的リソース アクセス

マルチ再開機能のサポートに役立つ機能として、新しいライフサイクル callback である Activity#onTopResumedActivityChanged() があります。

このメソッドは、アクティビティが最前面の再開アクティビティ位置を獲得した時点、またはそれを失った時点で呼び出されます。これは、アクティビティでマイクやカメラなど共有単一ユーザー リソースが使用されている場合に、そのことを知るために重要です。

protected 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 は排他的カメラ アクセスを保証するものではありません。カメラを使用する他のアプリが他の画面上で開かれている可能性があります。

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

アプリがフォーカスを失った場合、必ずしもカメラを解放する必要はありません。たとえば、再開して最前面になって新たにフォーカスを得たアプリとユーザーがやり取りする間、カメラのプレビューを続行しておくのがよいかもしれません。最前面の再開アプリではないアプリの実行を続行するのは良いことですが、切断する場合を適切に処理することが必要です。最前面の再開アプリがカメラを使用しようとすると、それを開くことができ、その結果、それまでカメラを使用していたアプリはアクセスを失います。そのアプリが再びフォーカスを得た時点で、もう一度カメラを開くことができます。

アプリが CameraDevice.StateCallback#onDisconnected() callback を受け取った後、カメラ端末に対するそれ以降の呼び出しでは CameraAccessException がスローされます。

マルチディスプレイ

将来的には、同時に複数の画面またはディスプレイをサポートする折りたたみ式スマートフォンが登場するかもしれません。その構成を処理することは、今日、デベロッパーが Chrome OS 上で投影画面の作業をするのとよく似ています。

Android 10 (API レベル 29) 以上 では、2 次ディスプレイ上のアクティビティがサポートされています。アクティビティが複数ディスプレイの端末で実行されている場合、ユーザーはアクティビティを別のディスプレイに移動できます。マルチ再開は、マルチスクリーンのシナリオにも適用されます。複数のアクティビティが同時にユーザー入力を受信することが可能です。

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

折りたたみ移行時に、アクティビティが 2 次ディスプレイに移ると、コンテキスト更新、ウィンドウのサイズ変更、および構成変更とリソースの変更が実行されます。アクティビティが構成変更を処理する場合、それは onConfigurationChanged() の中で通知されます。そうでない場合、再起動することになります。

アクティビティでは、onCreate および onConfigurationChanged が処理される場合に、その中で現在のディスプレイをチェックするようにしてください。ディスプレイが変更になった場合、リソースおよびレイアウトを更新するようにしてください。

アクティビティのために選択された起動モードで複数インスタンスが許可されている場合、2 次画面で起動するとアクティビティの新しいインスタンスが作成されることがあるという点に注意してください。2 つのアクティビティの両方が同時に再開することになります。

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

Android 8.0 で導入された既存のマルチディスプレイ API についての資料もご覧ください。

ディスプレイの切り欠き

折りたたみ式端末には、折りたたんだり広げたりした場合に、さまざまな切り欠きがある場合があります。切り欠きの問題を回避するには、ディスプレイの切り欠きに関するベスト プラクティスをご覧ください。

アクティビティ コンテキスト対アプリケーション コンテキスト

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

アクティビティ コンテキストにはディスプレイに関する情報が含まれており、それが表示されるディスプレイ領域に合わせて常に調整されます。現在のディスプレイ指標とリソースを取得するには、アクティビティ コンテキストを使用します。これは、コンテキストからの情報(Toast など)を使用する一部のシステム API にも影響します。

リソースとコンテキストは、アクティビティ ウィンドウ設定および親ディスプレイにより定義されます。現在のディスプレイを取得するには、次を使用します:

val activityDisplay = activity.windowManager.defaultDisplay

現在のアクティビティ ウィンドウ指標を取得するには、次を使用します:

val windowMetrics = DisplayMetrics()
activityDisplay.getMetrics(windowMetrics)

または:

val windowMetrics = activity.resources.displayMetrics

2 次画面の使用

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

val dm = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val displays = dm.displays

特定のディスプレイに関する情報を取得するには、Display クラスを使用します:

  • ディスプレイ指標により、画面のサイズ、解像度、密度に関する情報が得られます。
  • ディスプレイが安全かどうかを確認するには、フラグ を確認します。

ディスプレイ上でアクティビティを起動できるかどうかを判別するには:

activityManager.isActivityStartAllowedOnDisplay(context, displayId, intent)

また、ディスプレイ上でアクティビティを起動するには:

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

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

Android では、すでにソフトウェア キーボード、壁紙、およびランチャーがサポートされています。

ソフトウェア キーボード

ディスプレイがシステム デコレーションをサポートするように設定されている場合、システムキーボードを 2 次画面に表示できます。そのディスプレイ上でテキスト フィールドに入力が必要な場合、入力メソッド エディタ(IME)が自動的に表示されます。

2 次ディスプレイ上のキーボード。

壁紙

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

スマートフォンおよび 2 次ディスプレイ上の壁紙。

ランチャー

2 次画面専用アクティビティを提供するための新しいインテント ファイル カテゴリ SECONDARY_HOME があります。このアクティビティのインスタンスは、ディスプレイごとに 1 つずつシステム デコレーションをサポートするすべてのディスプレイ上で使用されます。

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

アクティビティには、複数インスタンスを妨げることがなく、複数の異なる画面サイズに適応可能な起動モードがなければなりません。起動モードを singleInstancesingleTask にすることはできません。

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

スマートフォン上のマテリアル デザイン ランチャー。

2 次ディスプレイ上のマテリアル デザイン ランチャー。

テスト

アプリを折りたたみ式対応にするには、アプリが次のことにどう対応するかをテストする必要があります:

  • 構成の変更
  • マルチウィンドウおよびマルチ再開
  • サイズ変更と新しい画面縦横比

折りたたみ式エミュレータ

AOSP エミュレータでは、折りたたみ式端末がサポートされています。それによりデベロッパーは、アプリを折りたたみのシナリオでテストできます。

7.3’’ 折りたたみ式エミュレータ

7.3" ディスプレイ 解像度 論理ディスプレイ
サイズ X Y 密度 Dpi サイズ
広げた状態 7.3 1536 2152 420
折りたたんだ状態 4.6 840 1960 420 標準

8’’ 折りたたみ式エミュレータ

8" ディスプレイ 解像度 論理ディスプレイ
サイズ X Y 密度 Dpi サイズ
広げた状態 8.03 2200 2480 420
折りたたんだ状態 6.62 1148 2480 420 標準

AOSP 折りたたみ式エミュレータ。

マルチディスプレイのテスト

強制デスクトップモードと呼ばれる新しいデベロッパー オプションを使用すると、デベロッパーは、すべての 2 次ディスプレイ上でシステム デコレーション サポートをオンにすることができ、デフォルト ディスプレイではなくそこにマウス ポインタが表示されます。[フリーフォーム ウィンドウを有効にする] と共に [強制デスクトップ] を使用すると、マルチ ウィンドウでのデスクトップ エクスペリエンスおよびウィンドウのサイズ変更の機能がシミュレートされます。

Pixel 上では、ディスプレイ シミュレーションを使用してそれを試すことができます。あるいは、HDMI または USB C 上のディスプレイ ポートをサポートする端末があれば、有線接続を使用してのテストを実施できます。

ディスプレイ シミュレーション。