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
メソッドを使用します。
getMaximumWindowMetrics()
: システムで可能な最大のウィンドウ表示状態を表すWindowMetrics
を返します。getCurrentWindowMetrics()
: システムの現在のウィンドウ表示状態を表すWindowMetrics
を返します。
Jetpack WindowManager ライブラリ メソッド computeMaximumWindowMetrics()
および computeCurrentWindowMetrics()
は、同じ機能を提供するとともに、API レベル 14 までの下位互換性を維持します。
折りたたみ式モード
折りたたみ式デバイスには、ディスプレイの折り目があるものと、ディスプレイを 2 つの部分(通常は半分ずつ)に分けるヒンジが付いているものがあります。ヒンジ付きのデバイスは、スパンモードのときの Microsoft Surface Duo のように、ヒンジの後ろをまたいでコンテンツを表示する機能を備えている場合があります。デバイスによっては、二つ折りの形状や、Samsung のフレックス モードのような他の形状を構成できるものもあります。
Jetpack WindowManager ライブラリを使用すると、デバイスに依存しない方法でデバイスのモード、構成の変更、表示機能に反応できます。詳しくは、新しい Jetpack WindowManager ライブラリによる新しいフォーム ファクタのサポートに関するブログ投稿をご覧ください。
形状
折りたたみ式デバイスは、FoldingFeature
状態定数 FLAT
と HALF_OPENED
に対応する以下の形状をサポートできます。FoldingFeature
クラスは、Jetpack WindowManager ライブラリに含まれています。FoldingFeature
は、ヒンジまたはディスプレイの折り目があるデバイスを識別します。FoldingFeature
は DisplayFeature
インターフェースを実装しています(デバイス エコシステムの拡大に伴い、このインターフェースは新しいディスプレイ タイプで実装できます)。
![]() |
![]() (テーブルトップ形状) |
デバイスの形状を取得するには、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 をサポートするデバイスの場合は、有線接続を使用します。
シミュレートされたディスプレイ。