ウィンドウ管理

Chrome OS では、複数のウィンドウで Android アプリを実行できます。図 1 に示すように、アプリはウィンドウ コンテナにレンダリングされます。ウィンドウ コンテナのサイズはデバイスのフォーム ファクタによって決まります。

図 1: さまざまなデバイスのアプリ ウィンドウ

ウィンドウのサイズ変更

図 2 に示すように、Chrome OS ユーザーは、画面の右下隅をドラッグする通常の方法で、アプリ ウィンドウのサイズを変更できます。

図 2: サイズ変更が可能なアプリ ウィンドウ

ウィンドウのサイズ変更には、次の 2 つのオプションがあります。

  • 構成変更に動的に対応する。これを行うには、onConfigurationChanged(..) を呼び出して、たとえば android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" をアクティビティのマニフェストに追加します。構成変更の処理の詳細については、構成変更の処理に関するドキュメントをご覧ください。
  • システムにアクティビティを再起動させる。この場合、onSaveInstanceState を実装し、ViewModel アーキテクチャ コンポーネントを使用して、前回保存したときの状態を復元する必要があります。

このページでは、アプリのウィンドウが正しく起動し、スムーズにサイズ変更され、サイズが変更されてもすべてのコンテンツが表示されるようにする方法を説明します。

ウィンドウのサイズ

アクティビティは、起動するたびに自身のウィンドウのサイズを読み取り、現在の構成に従ってコンテンツを配置する必要があります。

現在の構成を確認するには、現在のアクティビティで getResources().getConfiguration() を呼び出します。バックグラウンド アクティビティまたはシステム リソースの構成は使用しないでください。バックグラウンド アクティビティにはサイズがなく、システム構成にはサイズと向きが競合する複数のウィンドウが含まれている可能性があるため、使用可能なデータを抽出できません。

ウィンドウのサイズと画面のサイズは同じではないことにご注意ください。DP 単位のウィンドウ サイズを取得するには、Activity.getResources().getConfiguration().screenWidthActivity.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)) にリスナーを追加します。アプリがアートワークを事前にスケーリングしている場合は、解像度が変更されるたびにこれを行う必要があります。

フリーフォームのサイズ変更

Chrome OS では、ウィンドウのサイズを自由に変更できます。つまり、ユーザーはウィンドウの幅、高さ、画面上の位置を変更できます。多くの 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) を呼び出すと、不必要なウィンドウのサイズ変更が発生します。これはユーザーを混乱させるばかりか、アプリで処理できないと再起動が発生する可能性もあります。向きはマニフェストなどで一度だけ設定し、必要な場合にのみ変更することをおすすめします。

初期起動サイズ

以下の方法で、アプリの初期起動サイズを指定できます。

  • パソコン環境でのみ起動サイズを使用する。これにより、ウィンドウ マネージャから適切な表示範囲と向きが示されます。デスクトップ モード用のカスタマイズ設定を指定するには、<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) を作成して使用します。空の四角形を指定すると、アプリを最大化できます。

その他の考慮事項

Chrome OS で Android アプリを扱う際のその他の考慮事項を示します。

  • アクティビティの onDestroy メソッドで finish() を呼び出さないでください。これを行うと、サイズ変更時にアプリが閉じられ、再起動が必要な場合でも再起動されません。
  • TYPE_KEYGUARDTYPE_APPLICATION_MEDIA など、互換性のないウィンドウ タイプは使用しないでください。
  • 以前に割り当てたオブジェクトをキャッシュすることで、アクティビティの再起動を高速に行えるようにします。
  • ユーザーにアプリのサイズを変更してほしくない場合は、マニフェスト ファイルで android:resizeableActivity=false を指定してください。
  • アプリをテストして、ウィンドウのサイズ変更が適切に処理されることを確認してください。