デバイスの互換性モード

Android では、画面の向きやサイズ変更の制限を宣言するアプリに対して、互換性モードが有効になります。互換性モードを使用すると、大画面デバイスや折りたたみ式フリップフォンで許容されるアプリの動作が確保されますが、ユーザビリティは最適とはなりません。

アプリごとのオーバーライドを使用すると、デバイス メーカー、仮想デバイスの所有者1、ユーザーはアプリの動作を変更して、アプリのレイアウトを改善したり、特定のデバイスでアプリが動作しなくなったりしないようにできます。

Android 16

Android 16(API レベル 36)では、画面の向き、アスペクト比、アプリのサイズ変更の制限が無視され、最小幅が 600 dp 以上のフォーム ファクタでのアプリのレイアウトが改善されます。

API レベル 36 を対象とするアプリでは、アプリごとの次のオーバーライドは機能しません。

無効にする

アプリは API レベル 36 をターゲットにできますが、Android 16 の動作をオプトアウトすることもできます。この場合、OVERRIDE_ANY_ORIENTATION_TO_USER は適用されません。

マニフェスト プロパティを宣言する

API レベル 36 の動作をオプトアウトするには、PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY マニフェスト プロパティを宣言します。

特定のアクティビティをオプトアウトするには、<activity> 要素でプロパティを設定します。

<activity ...>
    <property
        android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
        android:value="true" />
    ...
</activity>

アプリ全体でオプトアウトするには、<application> 要素でプロパティを設定します。

<application ...>
    <property
        android:name="android.window.PROPERTY_COMPAT_ALLOW_RESTRICTED_RESIZABILITY"
        android:value="true" />
    ...
</application>

参照デバイス

次のデバイスでは、構成が特殊であるか、アプリで十分にサポートされていない構成であるため、アプリごとのオーバーライドが必要になることがあります。

  • タブレット: Google Pixel Tablet など、一部のタブレットでは自然な向きが横向きになっています。Display#getRotation()Surface.ROTATION_0 を返す場合、デバイスは自然な向きです。アプリが ROTATION_0 を縦向きと想定している場合、アプリのレイアウトとカメラ プレビューがデバイスのディスプレイと一致しないことがあります。
  • 横向きの折りたたみ式デバイス: Google Pixel Fold などの一部の折りたたみ式デバイスは、折りたたんだ状態では縦向きですが、開いた状態では横向きになります。アプリが展開時の向きを縦向きと想定している場合、ちらつきのループやレイアウトの問題が発生する可能性があります。
  • 折りたたみ式フリップ スマートフォン: 折りたたみ式フリップ スマートフォンは、通常、縦向きです。ただし、折りたたんだ状態では、通常、横向きの小さなディスプレイが表示されます。アプリは、ディスプレイのさまざまな向きを識別して対応する必要があります。
  • 外部ディスプレイ: 一部のデバイスでは、接続された外部ディスプレイでデスクトップ ウィンドウ セッションを開始できます。アプリは、画面サイズや解像度などの情報を外部ディスプレイにクエリする必要があります。そうしないと、アプリがディスプレイについて誤った想定を行い、アプリの動作が正しくなくなる可能性があります。
  • 車のディスプレイ: 多くの車のディスプレイは横向きですが、すべてではありません。自動車のディスプレイ向けの駐車時向けアプリの開発は、タブレット向けの開発と似ています。

互換性に関する一般的な問題

互換性の問題は、主にアプリの向きの制限、サイズ変更やアスペクト比の制限、カメラ プレビューの向きの誤った処理、API の誤用により発生します。

レターボックス表示

レターボックス表示にすると、アプリは画面の中央に配置されます。大画面の場合は、アクセスしやすいように片方の側に寄せて表示されます。使用されていないディスプレイ領域(アプリの側面または上下)にはマット(単色のバーまたはぼかし壁紙)が表示されます。

大画面のデバイスでは、レターボックス表示になることが多くなります。デバイスのディスプレイの寸法やアスペクト比が通常は標準のスマートフォンとは異なりますが、ほとんどのアプリは標準のスマートフォン用に設計されているためです。

図 1. アプリが縦向きに制限されているため、横向きのタブレットや折りたたみ式デバイスではレターボックス表示されます。

問題

画面の向きやアスペクト比が固定されているか、サイズ変更ができないため、アプリが一部のディスプレイ構成をサポートしません。

アプリの向きとサイズ変更を制御する設定としては、たとえば次のものがあります。

  • screenOrientation: アプリの固定の向きを指定します。アプリでは Activity#setRequestedOrientation() を使用して、実行時の向きを設定することもできます。

  • resizeableActivity: システムがさまざまなディメンションのウィンドウに合うようにサイズ変更できるかどうかを示します。Android 11(API レベル 30)以前では、アプリがマルチ ウィンドウ モードをサポートするかどうかを指定します。Android 12(API レベル 31)以降では、アプリが小さい画面(コンパクトなウィンドウ サイズクラス)でマルチウィンドウ モードをサポートするかどうかを指定します。Android 12 以降では、この設定にかかわらず、アプリは大画面(中または拡大されたウィンドウ サイズクラス)でのマルチウィンドウ モードをサポートします。

  • maxAspectRatio: アプリがサポートする最大アスペクト比を指定します。maxAspectRatio を設定できるのは、resizeableActivityfalse に設定しているアプリのみです。

  • minAspectRatio: アプリがサポートする最小アスペクト比を指定します。minAspectRatio を設定できるのは、resizeableActivityfalse に設定しているアプリのみです。

最適化

アプリは、すべてのデバイスとマルチウィンドウ モードのディスプレイの向きとサイズをサポートする必要があります。アプリのレイアウトとアプリのマニフェスト ファイルから、向きと固定アスペクト比の制限をすべて削除してください。

互換性の対応策

画面の向きやアスペクト比が固定されているアプリが、サイズや画面の向きがアプリで直接サポートされていないウィンドウで実行されている場合、Android では、継続性を維持するためにアプリがレターボックス表示されます。

Android 12(API レベル 31)以降、12L(API レベル 32)を含め、プラットフォームではレターボックス表示のアプリについてさまざまな機能強化が行われています。UI の機能強化はデバイス メーカーが実装します。これらの改善点を適用するためにアプリ側で追加の開発作業を行う必要はありません。

Android 12(API レベル 31)では、デバイス メーカーが設定できる以下の外観設定が強化されました。

  • 角丸: アプリ ウィンドウの角が洗練された印象になっています。
  • システムバーの透明度: アプリの上に重なるステータスバーとナビゲーション バーは半透明になり、バーのアイコンがレターボックスの背景の上に常に表示されます。
  • アスペクト比の設定が可能: アプリのアスペクト比を調整して、アプリの外観を改善することができます。

図 2. UI の機能が強化されたレターボックス表示のアプリ

12L(API レベル 32)では、次のような機能が改善されています。

  • 位置の設定が可能: デバイス メーカーは操作性を考慮して、大画面ディスプレイの左右どちら側にもアプリを配置できます。

  • 再起動ボタンのデザイン変更: デバイス メーカーはサイズ互換モードによって、再起動ボタンをユーザーにわかりやすいデザインにすることができます。

Android 13(API レベル 33)では、レターボックス表示されたアプリを画面上に配置する方法や、分割画面モードでのレターボックス表示に関するユーザー向け情報ダイアログが追加されています。

図 3. ユーザー向け情報ダイアログが表示された、レターボックス表示のアプリ。

サイズ互換モード

サイズ互換モードは、アプリのアスペクト比を維持し、再起動コントロールを含むレターボックス表示です。ユーザーはこのコントロールによりアプリを再起動してディスプレイを再描画できます。Android は、サイズ変更不可のアプリに対して、サイズ互換モードを適用します。アクティビティのディメンションと互換性のないディスプレイ コンテナにアクティビティが移ると、システムはアプリを再スケーリングして、少なくとも 1 つのディメンションがデバイスのディスプレイに収まるように表示されます。

たとえば、次のようなデバイス設定を変更すると、サイズ互換モードがトリガーされます。

  • デバイスの回転
  • 折りたたみ式デバイスの折りたたみと展開
  • 全画面モードと分割画面モードの切り替え

問題

一般的にサイズ互換モードが適用されるのは、画面の向きまたはアスペクト比が制限され、サイズ変更不可に設定(またはシステムによって決定)されているアクティビティです。

次のいずれかの条件を満たすアプリは、サイズ変更が可能と判断されるため、サイズ互換モードにはなりません。

アプリがこれらの条件のいずれかを満たしていない場合は、サイズ変更不可とみなされ、サイズ互換モードになる可能性があります。

最適化

アプリはすべてのディスプレイ サイズをサポートする必要があります。アプリ マニフェストで <activity> 要素または <application> 要素の android:resizeableActivity 属性を true に設定し、アプリをサイズ変更可能にします。アプリのレスポンシブ/アダプティブ レイアウトを設計します。詳しくは、各種のディスプレイ サイズをサポートするマルチウィンドウ モードをサポートするをご覧ください。

互換性の対応策

Android でアプリがサイズ互換性モードになるのは、アプリを再スケーリングして、少なくとも 1 つのディメンションがディスプレイ ウィンドウに収まるようにすることで、レターボックス アプリの表示を改善できるとシステムで判断された場合です。システムは、アプリのプロセスを再作成する再起動コントロールを表示し、アクティビティを再作成してディスプレイを再描画します。プロセスとスレッドの概要もご覧ください。

ディスプレイ互換性モード

ディスプレイ互換モードでは、アプリが異なるディスプレイ間を移動する際にアプリが再起動されるのを防ぎます。アプリが再起動されると、カラーモードタッチスクリーンの可用性画面密度などの設定変更がトリガーされる可能性があります。

安定性と継続性を向上させるため、ゲームではディスプレイ互換モードがデフォルトで有効になっています(android:appCategory フラグに基づく)。サイズ互換モードとは異なり、ディスプレイ互換モードではアプリの構成はフリーズされません。アプリは onConfigurationChanged() コールバックなどの API を通じてすべての構成更新を引き続き受け取ることができますが、中断を伴う再起動は免れます。つまり、onConfigurationChanged() などの API を適切にサポートしているゲームは、ディスプレイ互換モードであっても UI をレスポンシブに更新できます。

ディスプレイ互換モードを無効にしてアプリで構成変更を処理するには、アプリの AndroidManifest.xml ファイルで構成変更のサポートを宣言し、onConfigurationChanged() コールバックで構成変更を処理します。

<activity
    android:name=".MyGameActivity"
    android:configChanges="colorMode|touchscreen|density|...">
    ...
</activity>

ちらつきループ

アプリでサポートされていないディスプレイの向きがある場合、構成の変更時に新しい向きを繰り返しリクエストして無限ループが生じ、ディスプレイがちらついたり、アプリの回転が終わらなくなったりすることがあります。

問題

Android 12(API レベル 31)以降では、デバイス メーカーはアプリが指定した画面の向きの制限を無視し、代わりに互換モードを適用できるようになりました。たとえば、折りたたみ式デバイスは、デバイスの横向きのタブレット サイズの内部画面でアクティビティが表示される場合、アクティビティの android:screenOrientation="portrait" 設定を無視することがあります。

アプリの向きの制限が無視される場合、アプリは Activity#setRequestedOrientation() を呼び出して画面の向きをプログラムで設定できます。アプリが構成の変更を処理していない場合、この呼び出しによりアプリの再起動がトリガーされます(構成の変更を処理するをご覧ください)。再起動後に、アプリの向きの制限が再度無視され、アプリが setRequestedOrientation() の呼び出しを繰り返し、その呼び出しによってアプリの再起動がトリガーされるという自動継続ループが発生します。

また、デバイスの画面の自然な向き(Android によって判断される通常の向き)が横向きの場合にも、この問題が発生することがあります(アスペクト比が横向きのデバイスで Display#getRotation() を呼び出すと Surface.ROTATION_0 が返されます)。従来、Display.getRotation() = Surface.ROTATION_0 の場合、アプリではデバイスが縦向きになっていると判断されていましたが、一部の折りたたみ式デバイスの内部画面や一部のタブレットなどでは、そうでない場合もあります。

折りたたみ式インナー ディスプレイで横向きになっているアプリの場合、画面の回転を確認し、ROTATION_0 の値を受け取り、デバイスの自然な向きが縦向きであると想定し、setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT ) を呼び出してアプリのレイアウトを再構成する可能性があります。アプリが(横向きで)再起動すると、画面の回転を再度確認し、ROTATION_0 の値を受け取り、setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) を呼び出すという無限ループが継続する可能性もあります。

最適化

アプリが以下のことを行わないようにする必要があります。

  • アクティビティの onCreate() メソッドで Activity#setRequestedOrientation() を使用してデフォルトの向きを設定する。構成の未処理の変更により画面の向きのリクエストが予期せずトリガーされる可能性があります。
  • デバイスの自然な向き(ROTATION_0)が縦向きであると想定する
  • 現在のウィンドウ サイズに関係のないシグナルに基づいて向きを設定する。たとえば、Display#getRotation()FoldingFeature の有無、非推奨 API などです。

互換性の対応策

Android は次の場合に Activity#setRequestedOrientation() の呼び出しを無視します。

  • メソッドに対する前回の呼び出しからすでにアクティビティが再開しているか、カメラ互換性による強制回転処理が有効になっている(下記のカメラ プレビューを参照)。

    デバイス メーカーは、OVERRIDE_ENABLE_COMPAT_IGNORE_REQUESTED_ORIENTATION を使用してこの動作をアプリに適用できます。

  • アクティビティが 1 秒に 2 回以上、画面の向きのリクエストを行った。これは、ループが発生したことを示しています。Android はループ内の 2 つのリクエストのうち、アプリの表示領域を最大化するリクエストを使用します。

    デバイス メーカーは、OVERRIDE_ENABLE_COMPAT_IGNORE_ORIENTATION_REQUEST_WHEN_LOOP_DETECTED を使用してこの動作をアプリに適用できます。

  • 仮想デバイスのオーナーが、一部のデバイスでメソッド呼び出しをオーバーライドしました。

カメラ プレビュー

タブレット、ノートパソコン、折りたたみ式ディスプレイでは、カメラアプリのカメラ プレビュー(またはビューファインダー)がずれたり、歪んだりすることがあります。

問題

Android 互換性定義ドキュメントでは、カメラのイメージ センサーの向きは、カメラの長辺と画面の長辺が平行となる向きにしなければならないとされています。

多くのアプリは、デバイスの向きとカメラのセンサーの向きが縦向きであることを前提としています。これは、標準のスマートフォンでは妥当な想定です。しかし、タブレットやノートパソコン、およびそれらのデバイスのカメラセンサーでは自然な向きが横向きであることがあります。また、折りたたみ式などの新しいフォーム ファクタでは、自然な向きが複数存在したり、複数のカメラセンサーで向きが異なることがあります。

アプリが想定しないカメラの向きでアクティビティを開始したり、またはカメラやデバイス画面(折りたたみ式デバイス用)を切り替えると、カメラ プレビューの位置がずれたり、歪んだりすることがあります。

最適化

カメラアプリは、正しく調整、拡大縮小されたカメラ プレビューを表示するために、デバイスの向きとカメラのセンサーの向きを正しく識別して管理する必要があります。アプリは、デバイスの回転、センサーの回転、画面またはウィンドウのアスペクト比を計算し、その結果をカメラ プレビューに適用する必要があります。詳しくは、カメラ プレビューカメラ ビューファインダーの概要をご覧ください。

互換性の対応策

Display#getRotation()Surface.ROTATION_0 を返す場合、デバイスは自然な向きです。システムはデバイスの自然な向きから CameraCharacteristics.SENSOR_ORIENTATION を計算します。Android は、縦向き限定のアプリの縦向きウィンドウを、デバイスの自然な向きに合わせます。ほとんどのアプリではこの処理が想定されています。また、センサーの向きが横向きで、カメラ プレビューが縦向きの場合は、カメラセンサーの画像を切り抜きます。具体的な対応策は次のとおりです。

  • 縦向き限定のアプリでカメラ プレビューを強制的に回転する: 縦向き限定のアプリでは、デバイスの自然な向きとカメラセンサーの向きが縦向きであることを前提としています。ただし、Android 12(API レベル 31)以降では、デバイス メーカーが画面の向きの指定を無視した場合、複数のデバイスの向きでアプリを実行できます。

    縦向き限定のアプリがカメラに接続されている場合、Android はアプリを強制的に回転させて、アプリの縦向きのウィンドウをデバイスの自然な向きに合わせます。

    一部のタブレット(リファレンス デバイスを参照)では、デバイスの自然な向きに合わせて、縦向きのウィンドウが回転し、縦向きで全画面表示されます。アプリは強制回転後に全画面表示されます。

    折りたたみ式デバイスの横向きの内部画面(リファレンス デバイスを参照)では、広げた状態の自然な向きに合わせて、縦向き限定のアクティビティが横向きに回転します。強制回転後にアプリがレターボックス表示されます。

  • 内部の前面カメラの切り抜き: 一部の折りたたみ式デバイスの内部の前面カメラセンサーは横向きです。Android では、折りたたみ式デバイスのインナー ディスプレイでカメラ プレビューを強制的に回転させるほか、内部の全面(横向き)カメラの画角を切り抜いて、センサーがデバイスの向きと反対の視界を捉えるようにします。

  • カメラ プレビューを強制的に更新する: 強制回転後、システムがアクティビティ メソッド onStop() および onStart()(デフォルト)、または onPause() および onResume()(アプリごとの OVERRIDE_CAMERA_COMPAT_ENABLE_REFRESH_VIA_PAUSE オーバーライドにより適用)を切り替え、カメラ プレビューが適切に表示されるようにします。

  • アスペクト比のスケーリング: 強制回転したカメラ プレビューのアスペクト比が、大きい方の最小アスペクト比となるように動的に変更されます。これにより、カメラ プレビューが適切に拡大縮小されます。

アプリがカメラ プレビューを正しく処理していれば、アプリ デベロッパーはこれらの回避策をオーバーライドできます。アプリごとのオーバーライドをご覧ください。

よく誤用される API

Android でマルチウィンドウ モードなどの機能や折りたたみ式デバイスなどのデバイスのサポートが追加されると、それまでの API は非推奨になり、すべてのディスプレイ サイズとデバイス フォーム ファクタで機能する最新の API に置き換えられます。ただし、下位互換性のため、非推奨の API も引き続き使用できます。

一部の View API は特別な目的のために設計されていますが、この目的をデベロッパーが十分に理解しているとは限りません。

問題

デベロッパーが、非推奨の Display API を引き続き使用し、API がデバイスの表示領域の境界ではなくアプリの境界を返すものと誤った想定をします。また、デベロッパーが一般的なディスプレイの指標を取得するために特別な用途の View API を誤って使用している場合もあります。その結果、アプリ ウィンドウのサイズ変更イベント後に UI 要素を再配置すると計算が不正確になり、レイアウトの問題が発生します。

非推奨でよく誤用される Display API:

詳しくは、マルチウィンドウ モードをサポートするをご覧ください。

誤用される View API:

最適化

UI 要素の配置に、物理的なディスプレイ サイズを使用しないでください。WindowMetrics に基づいて、次の WindowManager API などの API にアプリを移行します。

互換性の対応策

2 つのオーバーライドで、非推奨の Display API と誤用された View API を調整し、アプリの境界を返すようにしました(Display API 用の ALWAYS_SANDBOX_DISPLAY_APIS と、View API 用の OVERRIDE_SANDBOX_VIEW_BOUNDS_APIS)。ALWAYS_SANDBOX_DISPLAY_APIS は、サイズ互換モードの対象となるアプリにもデフォルトで適用されます。

透明アクティビティ

透明アクティビティは、透明な背景スタイルの結果です。以下に例を示します。

<style name="Transparent" parent="AppTheme">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@android:color/transparent</item>
</style>

Theme.MaterialComponents.Dialog などのダイアログに関連するテーマには、アクティビティを透明にするスタイルを設定できます。

透明アクティビティは、使用可能なディスプレイ領域をすべてカバーしているわけではありません。そのため、デバイスの回転、デバイスの開閉、マルチウィンドウ モードなどの構成変更に基づいて、利用可能なディスプレイ領域が変化する可能性があるため、管理が困難になる場合があります。

問題

透明アクティビティは、タスク アクティビティ スタックで透明アクティビティの下にある最初の不透明アクティビティの境界に従う必要があります。ただし、権限ダイアログを起動する不透明アクティビティは、トランポリン(別のアクティビティを起動してから消えるアクティビティ)である場合があります。そのため、透明な権限ダイアログ アクティビティを起動したトランポリン アクティビティの境界は、システムでは決定できません。

最適化

透明アクティビティは、タスクのアクティビティ スタック内で、その下にある不透明アクティビティのうち最上位のものから制約を継承します。不透明アクティビティは、透明アクティビティのライフサイクル(アクティビティの作成から破棄まで)の全体で使用できるようにする必要があります。このため、トランポリン アクティビティから権限のリクエストを開始しないでください。

トランポリン アクティビティが権限のリクエストを開始すると、ユーザーがダイアログに応答できるようになる前にトランポリン アクティビティが破棄されるため、ユーザーに権限ダイアログが表示されないことがあります。また、ダイアログ アクティビティのサイズと位置が正しく計算されないこともあります。

アプリは必ず、ユーザーが権限に関する決定を行うまで表示されたままの状態になっているアクティビティから権限のリクエストを開始する必要があります。

角丸

アクティビティは、背景の透明度を指定するスタイルが原因で透明になることも、アクティビティのコンテンツが使用可能なディスプレイ領域を埋めないことが原因で透明になることもあります。透明アクティビティが使用可能なディスプレイ領域を埋める場合、デバイス メーカーにより設定されていれば、システムにより角丸がアクティビティに自動的に適用されます。ただし、使用可能なスペースが透明アクティビティ(権限ダイアログなど)で埋まらない場合は、角丸を適用するかどうかを判断する必要があります。

使用可能なディスプレイ領域を権限ダイアログが埋めることはありません。このダイアログのレイアウトでは通常、LayoutParams.MATCH_PARENT ではなく LayoutParams.WRAP_CONTENT を使用するためです。

互換性の対応策

ユーザーがダイアログに応答するまで、ダイアログ アクティビティを開始するアクティビティを表示したままにします。

システムにより、透明アクティビティは、アクティビティ スタック内で透明アクティビティの下にある最初の不透明アクティビティから、以下に関連する制約を含むすべての制約を継承するようにします。

  • サイズ互換モード
  • 向き
  • アスペクト比

Unity ゲーム

Unity ゲームは Android 全画面モードまたはマルチウィンドウ モードで動作します。しかし、アプリがマルチウィンドウ モードになっていると、Unity ゲームの多くがフォーカスを喪失し、コンテンツの描画が停止します。

問題

Unity には、Unity 2019.4 で Android のマルチウィンドウ モードをサポートする Resizable Window オプションが追加されました。しかし、初期実装はマルチウィンドウ モードでのアクティビティのライフサイクルに正しく反応せず、アプリがフォーカスを喪失したときに UnityPlayer が再生を一時停止していました。プレーヤーにより、黒い画面、またはゲームの最後のフリーズしたフレームがレンダリングされていました。ゲームプレイは、ユーザーが画面をタップした場合にのみ再開されていました。Unity エンジンを使用するアプリの多くがこの問題に直面しており、マルチウィンドウ モードでは黒いウィンドウとしてレンダリングされます。

最適化

Unity を 2019.4.40 以降にアップグレードして、ゲームを再エクスポートします。Android Player 設定Resizable Window オプションをオンにしたままにします。そうしないと、ゲームがマルチウィンドウ モードで完全に表示されている場合でも、フォーカスされていない間はゲームが一時停止します。

互換性の対応策

デバイス メーカーは、アプリごとの OVERRIDE_ENABLE_COMPAT_FAKE_FOCUS オーバーライドを適用して、マルチ ウィンドウ モードでアプリに疑似フォーカス イベントを提供できます。オーバーライドすると、アクティビティはコンテンツを再描画できるようになり、ブラックアウトされなくなります。

デスクトップ ウィンドウ

アプリがデスクトップ ウィンドウ環境で実行される場合、追加の互換モードが発生する可能性があります。

向きがロックされているアプリは、自由にサイズ変更できます。アクティビティが縦向きにロックされている場合でも、ユーザーはアプリのサイズを変更して横向きにすることができます。

縦向きアプリが横向きにサイズ変更されるアニメーション。

ただし、アクティビティがサイズ変更不可(resizeableActivity = false)として宣言されている場合、アクティビティの UI は同じアスペクト比を維持しながらスケーリングされます。

アプリのサイズ変更のアニメーション。UI がデスクトップ ウィンドウに合わせて拡大されます。

デスクトップ ウィンドウでのカメラ プレビュー

デスクトップ ウィンドウのアプリがカメラ プレビューを開始すると、ビューファインダーの UI は元の縦横比を維持したまま拡大縮小されます。アプリ ウィンドウの残りの部分は自由にサイズ変更できます。

互換性の問題がないかアプリをテストする

アプリをテストして、さまざまなフォーム ファクタでどのように動作するかを確認するには、次のリソースを活用してください。

レターボックス表示になっているか

各アクティビティが、アプリで使用可能なディスプレイ領域をすべて使用できることを確認してください。まず、テストフォルダで次のコードを宣言します。

Kotlin

fun isLetterboxed(activity: AppCompatActivity): Boolean {
    if (isInMultiWindowMode) return false

    val wmc = WindowMetricsCalculator.getOrCreate()
    val currentBounds = wmc.computeCurrentWindowMetrics(this).bounds
    val maxBounds = wmc.computeMaximumWindowMetrics(this).bounds

    val isScreenPortrait = maxBounds.height() > maxBounds.width()

    return if (isScreenPortrait) {
        currentBounds.height() < maxBounds.height()
    } else {
        currentBounds.width() < maxBounds.width()
    }
}

Java

public boolean isLetterboxed(AppCompatActivity activity) {
    if (activity.isInMultiWindowMode()) {
        return false;
    }

    WindowMetricsCalculator wmc = WindowMetricsCalculator.getOrCreate();
    Rect currentBounds = wmc.computeCurrentWindowMetrics(activity).getBounds();
    Rect maxBounds = wmc.computeMaximumWindowMetrics(activity).getBounds();

    boolean isScreenPortrait = maxBounds.height() > maxBounds.width();

    return (isScreenPortrait)
        ? currentBounds.height() < maxBounds.height()
        : currentBounds.width() < maxBounds.width();
}

次に、テストを実行して動作をアサートし、ターゲット アクティビティがレターボックス表示されていないことを確認します。

Kotlin

@get:Rule
val activityRule = ActivityScenarioRule(MainActivity::class.java)

@Test
fun activity_launched_notLetterBoxed() {
    activityRule.scenario.onActivity {
        assertFalse(it.isLetterboxed())
    }
}

Java

@Rule
public ActivityScenarioRule<MainActivity> rule = new ActivityScenarioRule<>(MainActivity.class);

@Test
public void activity_launched_notLetterBoxed() {
    try (ActivityScenario<MainActivity> scenario =
        ActivityScenario.launch(MainActivity.class)) {
            scenario.onActivity( activity -> {
                assertFalse(activity.isLetterboxed());
            });
        }
}

理想的には、この種のテストは合格するまで実行し、アプリのアクティビティがアプリで使用可能なディスプレイ領域全体を使用しているとアサートします。すべてのデバイスタイプでアプリをテストして、動作が一貫していることを確認します。

アプリごとのオーバーライド

Android には、アプリに設定されている動作を変更できるオーバーライドが用意されています。たとえば、FORCE_RESIZE_APP オーバーライドは、アプリ マニフェストで resizeableActivity="false" が指定されている場合でも、サイズ互換モードをバイパスして、ディスプレイの寸法に合わせてアプリのサイズを変更するようシステムに指示します。

デバイス メーカーは、特定の大画面デバイスで、一部のアプリまたはすべてのアプリにオーバーライドを適用します。Android 14(API レベル 34)以降では、ユーザーはデバイス設定を通じてアプリにオーバーライドを適用できます。Android 16(API レベル 36)以降では、仮想デバイスのオーナーは、仮想デバイスのオーナーが管理する一部のデバイスにオーバーライドを適用します。

ユーザーのアプリごとのオーバーライド

Android 14 以降では、設定メニューでアプリのアスペクト比を変更できます。リファレンス デバイスなどの大画面デバイスは、メニューを実装します。

メニューには、デバイスにインストールされているすべてのアプリのリストが表示されます。ユーザーがアプリを選択し、アプリのアスペクト比を 3:4、1:1、全画面、またはデバイス メーカーが設定したその他の値に設定します。ユーザーは、アプリ マニフェストで指定されているアプリのデフォルトのアスペクト比にリセットすることもできます。

アプリは、次の PackageManager.Property タグを設定することで、互換性オーバーライドをオプトアウトできます。

  • PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE

    ユーザーのアスペクト比の互換性オーバーライドを無効にするには、アプリ マニフェストにプロパティを追加し、値を false に設定します。

    <application>
        <property
            android:name="android.window.
            PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_OVERRIDE"
            android:value="false" />
    </application>
    

    アプリはデバイスの設定のアプリリストから除外されます。ユーザーはアプリのアスペクト比をオーバーライドできません。

    プロパティを true に設定しても効果はありません。

  • PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE

    ユーザーのアスペクト比の互換性オーバーライドの全画面オプションをオプトアウトするには、アプリ マニフェストにプロパティを追加して、値を false に設定します。

    <application>
        <property
            android:name="android.window.PROPERTY_COMPAT_ALLOW_USER_ASPECT_RATIO_FULLSCREEN_OVERRIDE"
            android:value="false" />
    </application>
    

    デバイス設定のアスペクト比オプションのリストから、全画面表示オプションが削除されます。ユーザーはアプリに全画面オーバーライドを適用できません。

    このプロパティを true に設定しても効果はありません。

すべての画面に対応するようにアプリを最適化する: アプリにアスペクト比の制限を設定しないでください。ウィンドウ サイズ クラスを使用して、利用可能な表示スペースの大きさに応じてさまざまなレイアウトをサポートします。

デバイスのアプリごとのオーバーライド

デバイス メーカーと仮想デバイスの所有者(信頼できる特権アプリを選択)は、タブレット、折りたたみ式デバイス、ChromeOS デバイス、車載ディスプレイなどの特定のデバイスで、アプリごとにオーバーライドを適用します。リファレンス デバイスは、デフォルトで一部のオーバーライドをさまざまなアプリに適用する場合があります。

アプリはほとんどのオーバーライドをオプトアウトにできます(下記のアプリごとのオーバーライドの表をご覧ください)。

互換性フレームワークを使用すると、オーバーライドを有効または無効にしてアプリをテストできます(互換性フレームワーク ツールをご覧ください)。有効にすると、オーバーライドがアプリ全体に適用されます。

Android Debug Bridge(adb)を使用して、オーバーライドを有効または無効にしたり、アプリに適用するオーバーライドを確認したりすることもできます。

オーバーライドを有効または無効にする方法は次のとおりです。

adb shell am compat enable/disable <override name/id> <package>

リファレンス デバイスの場合、アプリに適用されるオーバーライドを確認してください。

adb shell dumpsys platform_compat | grep <package name>