ChromeOS では、複数のウィンドウで Android アプリを実行できます。図 1 に示すように、アプリはウィンドウ コンテナにレンダリングされます。ウィンドウ コンテナのサイズはデバイスのフォーム ファクタによって決まります。
図 1. さまざまなデバイスのアプリ ウィンドウ。
さまざまな画面サイズに対応するレイアウトを設計することが重要です。Android のガイドラインに沿ってさまざまな画面サイズをサポートしていれば、ChromeOS で実行した場合にもアプリは適切に動作します。
このページでは、アプリのウィンドウが正しく起動し、スムーズにサイズ変更され、サイズが変更されてもすべてのコンテンツが表示されるようにする方法を説明します。
初期起動サイズ
アプリの初期起動サイズは、次の方法でリクエストできます。
パソコン環境でのみ起動サイズを使用する。これにより、ウィンドウ マネージャから適切な表示範囲と向きが示されます。デスクトップ モード用のカスタマイズ設定を指定するには、
<activity>内に次のメタタグを追加します。<meta-data android:name="WindowManagerPreference:FreeformWindowSize" android:value="[phone|tablet|maximize]" /> <meta-data android:name="WindowManagerPreference:FreeformWindowOrientation" android:value="[portrait|landscape]" />静的な起動サイズを使用する。次の例に示すように、アクティビティのマニフェスト エントリ内で
<layout>を使用して、「固定」の起動サイズを指定します。<layout android:defaultHeight="500dp" android:defaultWidth="600dp" android:gravity="top|end" android:minHeight="450dp" android:minWidth="300dp" />動的な起動サイズを使用する。新しいアクティビティの作成時に、
ActivityOptions.setLaunchBounds(Rect)を作成して使用します。空の四角形を指定すると、アプリを最大化できます。
ウィンドウのサイズを変更する
図 2 に示すように、ChromeOS では、ユーザーは画面の右下隅をドラッグする通常の方法で、アプリ ウィンドウのサイズを変更できます。
図 2. サイズ変更可能なアプリ ウィンドウ。
View クラスを使用する場合、ウィンドウのサイズ変更を処理するには次の 2 つの方法があります。
onConfigurationChanged(..)を呼び出して、構成変更に動的に対応します。たとえば、アクティビティのマニフェストにandroid:configChanges="screenSize|smallestScreenSize|orientation|screenLayout"を追加できます。構成変更の処理について詳しくは、構成変更の処理をご覧ください。- システムにアクティビティを再起動させる。この場合、
onSaveInstanceStateを実装し、ViewModel アーキテクチャ コンポーネントを使用して、前回保存したときの状態を復元します。
Jetpack Compose を使用する場合、サイズ変更の動作はアクティビティの構成方法によって異なります。変更を動的に処理する場合、ウィンドウ サイズが変更されると再コンポーズがトリガーされます。アクティビティがシステムによって再起動されると、再起動後に初期コンポーズが発生します。いずれにしても、ウィンドウ サイズの変化に対応する Compose レイアウトを作成することが重要です。固定サイズを想定しないでください。
ウィンドウのサイズ
アクティビティは、起動するたびに自身のウィンドウのサイズを読み取り、現在の構成に従ってコンテンツを配置する必要があります。
現在の構成を確認するには、現在のアクティビティで getResources().getConfiguration() を呼び出します。バックグラウンド アクティビティまたはシステム リソースの構成は使用しないでください。バックグラウンド アクティビティにはサイズがなく、システム構成にはサイズと向きが競合する複数のウィンドウが含まれている可能性があるため、使用可能なデータを抽出できません。
ウィンドウのサイズと画面のサイズは同じではないことにご注意ください。DP 単位のウィンドウ サイズを取得するには、Activity.getResources().getConfiguration().screenWidth と Activity.getResources().getConfiguration().screenHeight を使用します。画面サイズを使用する必要はおそらくありません。
コンテンツ境界
ウィンドウのコンテンツ境界は、サイズ変更後に変更される可能性があります。たとえば、ウィンドウが大きくなりすぎて画面に収まらない場合、アプリが使用するウィンドウ内の領域が変更されます。次のガイドラインに沿って対応してください。
- Android のレイアウト プロセスを使用するアプリは、使用可能なスペースに自動的に配置されます。
ネイティブ アプリでは、利用可能な領域を読み込み、サイズ変更をモニタリングして、アクセス不能な UI 要素が生じないようにします。次のメソッドを呼び出して、このサーフェスの利用可能な初期サイズを決定します。
NativeActivity.mLastContent[X/Y/Width/Height]()findViewById(android.R.id.content).get[Width/Height]()
オブザーバーを使用して継続的なモニタリングを実施できます。
NativeActivity.onContentRectChangedNative()NativeActivity.onGlobalLayout()view.addOnLayoutChangeListener(findViewById(android.R.id.content))にリスナーを追加する
アプリでアートワークを事前にスケーリングしている場合は、解像度が変更されるたびにこれを行います。
フリーフォームのサイズ変更
ChromeOS では、ウィンドウのサイズを自由に変更できます。つまり、ユーザーはウィンドウの幅、高さ、画面上の位置を変更できます。多くの Android アプリは、フリーフォームのサイズ変更を意識せずに作成されています。以下の問題を考慮してください。
- 画面の位置が変わることがあります。ウィンドウから画面への座標変換と画面からウィンドウへの座標変換は、常にシステムによって行われます。
- Android のビューシステムを使用している場合、ウィンドウのサイズが変更されるとウィンドウ レイアウトが自動的に変更されます。
- ビューシステムを使用せずにサーフェスを扱う場合は、アプリ自体でサイズ変更を処理する必要があります。
- ネイティブ アプリでは、
mLastContentメンバーを使用するか、コンテンツ ビューを使用して初期サイズを決定します。 - アプリが実行中の場合は、
onContentRectChangedNativeイベントまたはonGlobalLayoutイベントをリッスンしてサイズ変更に対応します。 - アプリのサイズが変更されたときは、レイアウトとアートワークの再スケーリングまたは再読み込みを行い、入力領域を更新します。
全画面モード
全画面モードは、ストック Android の場合と同様に機能します。ウィンドウが全画面を占有していない場合、全画面表示の(すべてのシステム UI 要素を非表示にする)リクエストは無視されます。アプリを最大化すると、通常の全画面表示のメソッド、レイアウト、関数が実行されます。これにより、システム UI 要素(ウィンドウ コントロール バーとシェルフ)が非表示になります。
画面の向き
Android アプリの最も一般的な向きは、スマートフォンの通常の持ち方に合わせて、縦向きです。縦向きはスマートフォンには適していますが、横向きが通常であるノートパソコンとタブレットには適していません。アプリの利便性を損なわないように、両方の向きをサポートすることを検討してください。
一部の Android アプリは、デバイスを縦向きで持った場合、回転値が Surface.ROTATION_0 であると想定します。たしかに、ほとんどの Android デバイスではそのとおりです。しかし、アプリが特定の ARC モードである場合、縦向きの回転値が Surface.ROTATION_0 にならない場合があります。
加速度計などのセンサーを読み取りながら正確な回転値を取得するには、Display.getRotation() メソッドを使用し、それに応じて軸を入れ替えます。
ルート アクティビティと向き
Chromebook のウィンドウは、アクティビティ ウィンドウのスタックで構成されます。スタック内の各ウィンドウは、同じサイズと向きを持ちます。
パソコン環境では、向きとサイズが突然変わるとユーザーは混乱します。Chromebook のウィンドウ マネージャは、Android のサイドバイサイド モードと同様の方法でこの問題に対処します。つまり、スタックの最下位のアクティビティによって、その上にあるすべてのアクティビティの属性が決まります。これにより、新たに開始された縦向きでサイズ変更不可のアクティビティが、横向きでサイズ変更可に変わるという、想定外の状況が生じる可能性があります。
ここでデバイスモードの効果が現れます。タブレット モードでは向きがロックされず、Android での通常の動作と同じように、各ウィンドウの向きが保持されます。
向きに関するガイドライン
向きを処理する際のガイドラインは次のとおりです。
- 1 つの向きだけをサポートする場合は、そのことがアプリの起動前にウィンドウ マネージャによって認識されるように、マニフェストに情報を追加します。向きを指定する場合は、可能な限りセンサーの向きも指定します。これは、コンバーチブルであることが多い Chromebook で、上下逆に表示されるのを避けるためです。
- 選択された 1 つの向きを維持するようにします。マニフェストで 1 つの向きをリクエストした後、プログラムで別の向きを設定することは避けてください。
- ウィンドウのサイズに基づいて向きを変更する際には注意が必要です。小さな縦向きのウィンドウが固定され、ユーザーが大きな横向きのウィンドウに戻れなくなる場合があります。
- Chrome には、すべての使用可能なレイアウトを切り替えられるウィンドウ コントロールがあります。ユーザーは画面の向きのオプションを選択して、アプリを起動したときに適切なレイアウトで表示できます。アプリが縦向きと横向きの両方に対応している場合、デフォルトの設定は横向きになります。このオプションの設定は、アプリごとに保存されます。
- 向きの変更はできるだけ避けるようにします。たとえば、アクティビティの向きが縦向きであるのに、アプリが実行時に
setRequestedOrientation(LANDSCAPE)を呼び出すと、不必要なウィンドウのサイズ変更が発生します。これはユーザーを混乱させるばかりか、アプリで処理できないと再起動が発生する可能性もあります。向きはマニフェストなどで一度だけ設定し、必要な場合にのみ変更することをおすすめします。
その他の考慮事項
ChromeOS で Android アプリを扱う際のその他の考慮事項を示します。
- アクティビティの
onDestroyメソッドでfinish()を呼び出さないでください。これを行うと、サイズ変更時にアプリが閉じられ、再起動されません。 TYPE_KEYGUARDやTYPE_APPLICATION_MEDIAなど、互換性のないウィンドウ タイプは使用しないでください。- 以前に割り当てたオブジェクトをキャッシュすることで、アクティビティの再起動を高速に行えるようにします。
- ユーザーにアプリのサイズを変更してほしくない場合は、マニフェスト ファイルで
android:resizeableActivity=falseを指定してください。 - アプリをテストして、ウィンドウのサイズ変更が適切に処理されることを確認してください。