Chromebook での画面サイズの互換性

Android アプリを Chrome OS に実装する場合は、基本的なマルチウィンドウがサポートされます。Chrome OS 上の Android アプリは、無条件に全画面表示されるのではなく、フォーム ファクタに適したウィンドウ内に表示されます。

タスクとウィンドウのサイズ変更

アクティビティのウィンドウ サイズが可変のため、アクティビティの開始時には解像度を読み込む必要があります。また、onConfigurationChanged(..) を呼び出すことで解像度の変更に対応しなければなりません。たとえば、最大化時にユーザーの作業が失われないようにするには、次のいずれかを行います。

  • アクティビティのマニフェストに android:configChanges="screenSize|smallestScreenSize|orientation|screenLayout" を追加することで、設定変更を動的に処理します。
  • onSaveInstanceState を使用して以前の状態を復元し、できるだけシンプルに移行します。この方法は、再起動を要求するしか選択肢がない場合に適用します。

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

もう 1 つの重要な注意事項は、ウィンドウ コンテンツの表示範囲を変更できるということです。たとえば、ウィンドウが大きすぎて画面に収まらない場合は、アプリで使用するウィンドウ内の領域を変更できます。次のガイドラインを参考にしてください。

  • 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))
    アプリでアートワークを事前にスケーリングしている場合は、解像度が変更されるたびにこれを行う必要があります。

システムでは自由なサイズ変更をサポートしています。しかし、すべてのアプリがそれを考慮して作成されているとは言えません。以下に、考慮すべき点をいくつか示します。

  • サイズ変更はシームレスに処理します。サイズ変更は、さまざまな原因によりいつでも起こりえます。そのため、再起動が必要になった場合は、onSaveInstanceState を使用して可能な限り状態の保存と復元を行うことがとても重要です。これは、一般に Android でも有用です。
  • また、以前に割り当てたオブジェクトをキャッシュすることで、アクティビティの再起動を高速に行えるようにします。フレームワーク レイアウト メカニズムを使用しない場合(たとえば、アプリで OpenGL を使用してコンテンツをスケーリングする場合や、その他のロジックを使用する場合)は、onConfigurationChanged イベントをリッスンしてアクティビティの再起動を避ける必要があります。動的に処理できる変更イベントは、すべて確実に指定するようにしてください。
  • サイズを変更できないようにするには、マニフェスト ファイルでそのように指定します。
  • ウィンドウ サイズと画面サイズは異なるもので、画面サイズが必要になることはほぼありません。ウィンドウ サイズは、Activity.getResources().getConfiguration().screenWidthActivity.getResources().getConfiguration().screenHeight を使用して取得します(dp 単位)。

現在の設定を取得するには、常にアクティビティのリソースを使用し、そこから設定を取得します。そうしないと、画面プロパティなどの異なるものを参照することになります。

なお、画面上の位置も変更される可能性があります。そのため、ウィンドウ スペースから画面スペースへの変換やその逆の変換の計算には、必ずシステムを使用してください。

Android のビューシステムを使用している場合は、ウィンドウは自動的にサイズが変更されて配置されます。

アプリでビューシステムを使用せずにサーフェスを扱う場合は、独自にサイズ変更を処理する必要があります。

ネイティブ アプリでは mLastContent メンバーを使用するか、コンテンツ ビューを取得して初期サイズを取得する必要があります。

実行中のアプリでは、onContentRectChangedNative イベントや onGlobalLayout イベントをリッスンしてサイズ変更に対応します。

サイズが変更されると、アプリではレイアウトとアートワークを更新または再読み込みし、入力領域を更新する必要があります。

レイアウト

画面により多くの情報を表示するため、さまざまなレイアウトを指定したり、必要なサイズに応じてレイアウトを動的に生成したりできます。動的な生成は一般的には推奨されませんが、場合によっては選択肢になります。

レイアウト システムを使用しないアプリでは、設定変更のたびに再起動していては使い勝手が悪いため、これを避ける必要があります。このような設定変更は、ウィンドウ サイズの変更といった明白な理由だけでなく、デバイスモードの切り替わりなどの明白でない理由からも発生する可能性があります。たとえば、ノートパソコンからタブレットに切り替えると、物理キーボードが消えたという変更が報告されます。そのような場合に再起動が発生して、待たされたり、作業内容が予期せず消えてしまったりするのは、ユーザーにとって良いエクスペリエンスとは言えません。

動的なサイズ変更操作により非表示になった UI 要素に、コードからアクセスしないようにしてください。

ビュー階層変更のモニタリング

ウィンドウ コントロール キャプションを追加すると問題が発生することがあります。次の推奨事項を参考にしてください。

  • コンテンツがウィンドウの (0, 0) から始まるとは限りません。ウィンドウ コンテンツは、キャプションの高さの分だけオフセットされます。View.getLocationInWindow() を使用してビューの画面位置を確認し、正しいオフセットを取得します。
  • DecorViewcontentView のホルダーであるとは限りません。キャプションがウィンドウ階層の中に存在する場合は、DecorView とコンテンツ ビューの間に配置されます。そのため、次の点に注意してください。
    • DecorView 直下のビュー階層は変更しないでください。
    • DecorView の子要素のタイプが LinearLayout であるとは限りません。
  • Configuration.screenHeightDp がアプリのコンテンツ領域の高さとは限りません。キャプション ビューが存在する場合は、その分の高さが含まれています。Display.getSize() などについても同様です。

その他の注意事項

その他の注意事項を以下に示します。

  • アクティビティを常に全画面表示にする場合は、マニフェストに android:resizeableActivity="false" フラグを追加します。
  • エンドユーザーには、使用可能なすべてのレイアウトを切り替えられるよう、ウィンドウ コントロールが表示されます。画面の向きのオプションを正しく設定しておくことで、ユーザーがアプリを起動したときに適切なレイアウトで表示されるようにできます。アプリが縦向きと横向きの両方に対応している場合、横向きが可能な状況ではそれがデフォルトになります。このオプションの設定は、アプリごとに保存されます。
  • 向きの変更はできるだけ避けるようにします。たとえば、アクティビティの向きが PORTRAIT の場合にアプリから setRequestedOrientation(LANDSCAPE) が呼び出されると、ウィンドウ サイズの不要な変更が発生します。これにより、ユーザーを混乱させるばかりか、アプリで処理できない場合は再起動が発生する可能性もあります。向きをマニフェストなどで設定しておき、その後は必要な場合に限って変更する、というのが望ましい対応です。
  • アクティビティの onDestroy メソッドで finish() を呼び出さないでください。これを行うと、サイズ変更時にアプリが閉じられ、再起動が必要な場合でも再起動されません。
  • TYPE_KEYGUARDTYPE_APPLICATION_MEDIA など、互換性のないウィンドウ タイプは使用しないでください。

注: ウィンドウ サイズの変更が適切に処理されることを確認するため、アプリのテストを行うようおすすめします。