折りたたみ式デバイスに対応したアプリの設計

デバイスの前面を手前に向けて部分的に折りたたまれた折りたたみ式デバイス。

Android 10(API レベル 29)では、折りたたみ式デバイスのサポートが強化されています。

デバイスを広げて大きな画面を表示できるようにすると、ユーザビリティの面で次のようなプラスの影響があります。

  • 一般的に、画面が大きいほど臨場感が増します。
  • マルチウィンドウ モードでは、ユーザーはマルチタスクを実行できます。

デバイスを折りたたんだり広げたりすると、ディスプレイのサイズ、密度、アスペクト比が変化することがあります。これは Android 開発では新しい問題ではなく、折りたたみ式デバイスと無関係なユースケースでも懸案事項になっています。たとえば、次のようなユースケースがあります。

  • スマートフォンとタブレットで縦向きと横向きを切り替える
  • デスクトップ モードで Chrome OS 上の Android アプリのサイズを変更する
  • 複数のディスプレイを備えたデバイスを使用する

このページでは、折りたたみ式フォーム ファクタでアプリを正常に機能させるためのベスト プラクティスについて説明します。

また、Android 10 の変更点の概要説明にある折りたたみ式のサポートもご確認ください。

アプリの継続性

アプリは、折りたたみ式デバイスで実行されているとき、ある画面から別の画面に自動的に遷移することができます。遷移した後、アプリは同じ状態と同じ箇所で再開する必要があり、現在のタスクはシームレスに続行されなければなりません。

折りたたみ式デバイスが外側に折りたたまれる様子を表すアニメーション。

システムはデバイスが折りたたまれたり広げられたりする最中に構成の変更をトリガーするため、アプリは UI の状態を保存し、適切な方法で構成の変更に対応する必要があります。

注: 折りたたみ式デバイスには、さまざまな折りたたみ方法があります。たとえば、内側に折りたたむ(デバイスの内側にディスプレイを包むように折りたたむ)方法や、外側に折りたたむ(ディスプレイがデバイスを包むように折りたたむ)方法などです。

アプリのサイズを変更できるようにする

マルチ ウィンドウ モードでも、またディスプレイのサイズを動的に変更したときでも、アプリが動作するようにしなければなりません。アプリが実行される可能性があるフォーム ファクタおよび環境(折りたたみ式デバイス、デスクトップ モード、フリーフォーム ウィンドウなど)との互換性を最大限に高めるには、プロジェクトのマニフェスト ファイルの <application> セクションまたは <activity> セクションで resizeableActivity=true を設定します。さらに、分割画面モードや折りたたみ式デバイス エミュレータでアプリの動作をテストします。

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

たとえば、下記のアクティビティは maxAspectRatio とともに resizableActivity=false を設定しています。デバイスを広げたときは、アプリを互換モードにすることで、アクティビティの構成、サイズ、アスペクト比が維持されます。

広げられた表示領域を部分的に埋めるアプリが表示されている折りたたみ式デバイス。

resizeableActivity=false を設定してマルチウィンドウ モードを無効にした状態でアプリの継続性をサポートする場合は、マニフェスト ファイルの <application> 要素に次のメタデータを追加します。

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

supports_size_changes が true の場合にユーザーがデバイスを折りたたむか広げるかすると、アクティビティはウィンドウ サイズの変更に対応した方法で、変更された構成を適用します。

resizeableActivity を設定しなかった場合(または true に設定した場合)、アプリはマルチウィンドウ モードを完全にサポートするとともにサイズ変更可能であると見なされます。

一部の OEM は、アクティビティの表示領域が変更されるたびに小さな再起動アイコンを画面に追加する機能を実装しています。これにより、ユーザーは新しい構成でアクティビティを再開できます。

WindowManager を使用する

折りたたみ式デバイスも、それ以外のデバイスと同様にさまざまなウィンドウ モードをサポートしています。

ウィンドウ モードに関係なく、折りたたみ式デバイスで適切なアプリ境界を取得するには、次の WindowManager メソッドを使用します。

Jetpack WindowManager ライブラリ メソッド computeMaximumWindowMetrics() および computeCurrentWindowMetrics() は、同じ機能を提供するとともに、API レベル 14 までの下位互換性を維持します。

折りたたみ式モード

折りたたみ式デバイスには、ディスプレイの折り目があるものと、ディスプレイを 2 つの部分(通常は半分ずつ)に分けるヒンジが付いているものがあります。ヒンジ付きのデバイスは、スパンモードのときの Microsoft Surface Duo のように、ヒンジの後ろをまたいでコンテンツを表示する機能を備えている場合があります。デバイスによっては、二つ折りの形状や、Samsung のフレックス モードのような他の形状を構成できるものもあります。

Jetpack WindowManager ライブラリを使用すると、デバイスに依存しない方法でデバイスのモード、構成の変更、表示機能に反応できます。詳しくは、新しい Jetpack WindowManager ライブラリによる新しいフォーム ファクタのサポートに関するブログ投稿をご覧ください。

形状

折りたたみ式デバイスは、FoldingFeature 状態定数 FLATHALF_OPENED に対応する以下の形状をサポートできます。FoldingFeature クラスは、Jetpack WindowManager ライブラリに含まれています。FoldingFeature は、ヒンジまたはディスプレイの折り目があるデバイスを識別します。FoldingFeatureDisplayFeature インターフェースを実装しています(デバイス エコシステムの拡大に伴い、このインターフェースは新しいディスプレイ タイプで実装できます)。

縦向きの折りたたみ式デバイスが完全に広げられています。
FLAT
縦向きの折りたたみ式デバイスがテーブルトップの形状で半分広げられています。
HALF_OPENED
(テーブルトップ形状)

デバイスの形状を取得するには、FoldingFeature クラスを使用します。次の状態を直接チェックできます。

または、折りたたみ式デバイスの状態を抽象化した以下のプロパティを使用することもできます。

これらのプロパティを使用して、テーブルトップ モード(ヒンジまたは折りたたみが水平方向)やブックモード(ヒンジまたは折りたたみが垂直方向)などのさまざまな形状を認識します。

private fun isTableTopMode(foldFeature: FoldingFeature) =
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL

private fun isBookMode(foldFeature: FoldingFeature) =
        foldFeature.state == FoldingFeature.State.HALF_OPENED &&
            foldFeature.orientation == FoldingFeature.Orientation.VERTICAL

WindowInfoRepository クラスで利用可能な windowLayoutInfo Kotlin フローからイベントを収集することで、FoldingFeature 状態の変化について通知を受け取ることができます。

val windowInfoRepository = windowInfoRepository()
lifecycleScope.launch(Dispatchers.Main) {
    // The block passed to repeatOnLifecycle is executed when the lifecycle
    // is at least STARTED and is cancelled when the lifecycle is STOPPED.
    // It automatically restarts the block when the lifecycle is STARTED again.
    lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
        // Safely collects from windowInfoRepository when the lifecycle is
        // STARTED and stops collection when the lifecycle is STOPPED.
        windowInfoRepository.windowLayoutInfo
            .collect { newLayoutInfo ->
                // Check newLayoutInfo.displayFeatures to see if the
                // feature list includes a FoldingFeature, then check
                // the feature's data.
            }
    }
}

Jetpack WindowManager では、WindowInfoRepository の Java 互換インターフェースである WindowInfoRepositoryCallbackAdapter も利用できます。アダプターは、addWindowLayoutInfoListener でアプリのコールバックを登録することでアップデートを受け取ります。

アップデートの受け取りを停止するには、removeWindowLayoutInfoListener を使用してコールバックを削除します。

コールバックは、WindowLayoutInfo オブジェクトでデータを受け取ります。このオブジェクトには、ウィンドウの表示機能のリストが含まれています。情報にアクセスするには、displayFeatures プロパティを使用します。

class LayoutStateChangeCallback implements Consumer<WindowLayoutInfo> {
    @Override
    public void accept(WindowLayoutInfo windowLayoutInfo) {
      // Check windowLayoutInfo.displayFeatures to see if the
      // feature list includes a FoldingFeature, then check
      // the feature's data.
    }
}

これらの機能の使用方法とテスト方法を示すサンプルは GitHub にあります。

ヒンジ角度

Android 11 以降、ヒンジ付きの画面を備えたデバイスで実行されるアプリは、デバイスが TYPE_HINGE_ANGLE 値を提供するセンサーを搭載していて、ヒンジ角度の数値を提供する SensorEvent を報告する場合は、ヒンジの角度を判断できるようになりました。この測定値を使用すると、ユーザーがデバイスを操作するときに、きめ細かいアニメーションを実行できます。

特定の種類のアプリ(ランチャーや壁紙など)では正確なヒンジ角度を把握することが役に立つ場合もありますが、ほとんどのアプリでは、Jetpack WindowManager ライブラリを使用して形状を取得する必要があります。これは、現在市場に出回っているデバイス構成の多様性(将来的にはもっと種類が増えるはずです)により、形状への対応の信頼性が高まっているためです。

テスト

アプリを折りたたみ式デバイスで実行できるようにするには、以下に対するアプリの反応をテストする必要があります。

  • 構成の変更
  • マルチウィンドウ モードと複数のアプリの再開
  • サイズ変更と新しいディスプレイのアスペクト比

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

Android オープンソース プロジェクト(AOSP)には、折りたたみ式デバイスの機能をシミュレートするさまざまなデバイス エミュレータがあります。

Android Studio の Android Virtual Device(AVD)Manager では、折りたたみ式デバイスのエミュレータを使用して、簡単にアプリをテストできます。

デバイス エミュレータで折りたたみ式デバイスを広げたり折りたたんだりする様子を表すアニメーション。

折りたたみ式デバイス エミュレータ。

マルチディスプレイ

[デスクトップ モードに強制的に切り替え] 開発者向けオプションを使用すると、すべてのセカンダリ ディスプレイでシステム デコレーションのサポートを有効にすることができます。また、[デスクトップ モードに強制的に切り替え] を使用すると、マウスポインタはデフォルト ディスプレイではなく、セカンダリ ディスプレイに表示されます。[フリーフォーム ウィンドウの有効化] デベロッパー オプションとともに [デスクトップ モードに強制的に切り替え] を使用すると、マルチウィンドウ モードでのウィンドウのサイズ変更が可能なデスクトップ エクスペリエンスをシミュレートできます。

シミュレートされたディスプレイを使用して、複数のディスプレイを操作できます。USB-C を介して HDMI または DisplayPort をサポートするデバイスの場合は、有線接続を使用します。

さまざまなタイプのシミュレートされたセカンダリ ディスプレイを選択できるダイアログ ボックスが表示されているスマートフォン。

シミュレートされたディスプレイ。