サービスに関する最新情報

Android デバイスを接続ディスプレイにシームレスに拡張

所要時間: 7 分
Francesco Romano のプロフィールを表示
Francesco Romano Android デベロッパー リレーションズ エンジニア

Android でモバイル コンピューティングとデスクトップ コンピューティングを近づけるための大きなマイルストーンとして、Android 16 QPR3 リリースで、接続ディスプレイのサポートが一般提供されたことをお知らせします。

Google I/O 2025 で紹介したように、接続ディスプレイを使用すると、Android デバイスを外部モニターに接続して、デスクトップ ウィンドウ環境にすぐにアクセスできます。アプリは、フリーフォーム ウィンドウまたは最大化されたウィンドウで使用でき、ユーザーはデスクトップ OS と同じようにマルチタスクを行うことができます。

Google と Samsung は、Android 16 を搭載した Android エコシステム全体のデバイスを外部ディスプレイに接続したときに、シームレスでパワフルなデスクトップ ウィンドウ エクスペリエンスを提供できるよう、協力して取り組んできました。
この機能は、対応する Google Pixel および Samsung のスマートフォンを外部モニターに接続できるユーザーを対象に、対応デバイス* で一般提供が開始されました。これにより、フォーム ファクタに適応する、より魅力的で生産性向上アプリ エクスペリエンスを構築する新たな機会が生まれます。

仕組み

サポートされている Android スマートフォンまたは折りたたみ式デバイスを外部ディスプレイに接続すると、接続されたディスプレイで新しいデスクトップ セッションが開始されます。

接続されたディスプレイでのエクスペリエンスは、デスクトップでのエクスペリエンスに似ています。たとえば、アクティブなアプリを表示するタスクバーがあり、ユーザーはアプリを固定してすばやくアクセスできます。ユーザーは、接続されたディスプレイ上で、サイズを自由に変更できるウィンドウで複数のアプリを同時に並べて実行できます。

materialDisplay.gif

スマートフォンが外部ディスプレイに接続され、ディスプレイ上でデスクトップ セッションが実行されている間、スマートフォンは独自の状態を維持します。

デスクトップ ウィンドウをサポートするデバイス(Samsung Galaxy Tab S11 などのタブレット)を外部ディスプレイに接続すると、デスクトップ セッションが両方のディスプレイに拡張され、より広いワークスペースを利用できるようになります。2 つのディスプレイが 1 つの連続したシステムとして機能し、アプリ ウィンドウ、コンテンツ、カーソルをディスプレイ間で自由に移動できるようになります。

materialDisplay2.gif

外部ディスプレイに接続されたタブレット。デスクトップ セッションが両方のディスプレイに拡張されています。

重要な理由

Android 16 QPR3 リリースでは、接続されたディスプレイのエクスペリエンスを定義するウィンドウ動作、タスクバーの操作、入力の互換性(マウスとキーボード)を最終決定しました。また、ディスプレイを切り替える際にウィンドウをスケーリングし、アプリの再起動を回避する互換性処理も含まれています。


アダプティブ デザインの原則に基づいてアプリを構築すると、自動的にデスクトップのルック アンド フィールが適用され、ユーザーは違和感なくアプリを使用できます。アプリが縦向きに固定されている場合や、タッチ専用インターフェースを想定している場合は、今こそ最新化するタイミングです。

特に、コネクテッド ディスプレイで最適なアプリ エクスペリエンスを実現するための、次の重要なベスト プラクティスに注意してください。

  • Display オブジェクトが一定であると想定しない: アプリのコンテキストに関連付けられた Display オブジェクトは、アプリ ウィンドウが外部ディスプレイに移動された場合や、ディスプレイ構成が変更された場合に変化する可能性があります。アプリは、構成変更イベントを適切に処理し、ディスプレイ指標をキャッシュするのではなく、動的にクエリする必要があります。
  • 密度設定の変更を考慮する: 外部ディスプレイのピクセル密度は、メインのデバイス画面とは大きく異なる場合があります。レイアウトとリソースがこれらの変更に正しく適応し、UI の明瞭性とユーザビリティが維持されるようにしてください。レイアウトに密度非依存ピクセル(dp)を使用し、密度固有のリソースを提供して、UI が適切にスケーリングされるようにします。
  • 外部周辺機器を正しくサポートする: ユーザーが外部モニターに接続すると、デスクトップのような環境が作成されることがよくあります。これには、外付けキーボード、マウス、トラックパッド、ウェブカメラ、マイク、スピーカーの使用が含まれることがよくあります。キーボードとマウスの操作のサポートを改善する。

最新のツールでデスクトップの未来を構築する

デスクトップ エクスペリエンスの構築に役立つツールがいくつか用意されています。コア アダプティブ ライブラリの最新の更新情報を振り返ってみましょう。

新しいウィンドウ サイズクラス: 大、特大

Jetpack WindowManager 1.5.0 の最大のアップデートは、幅のウィンドウ サイズクラスに Large と Extra-large の 2 つが新たに追加されたことです。

ウィンドウ サイズクラスは、アダプティブ レイアウトの設計と開発に役立つ、独自のビューポート ブレークポイントの公式セットです。1.5.0 では、このガイダンスを一般的なタブレットのサイズを超える画面にも拡張しています。

新しい幅のブレークポイントは次のとおりです。

  • 大: 幅が 1,200 ~ 1,600 dp の場合
  • 特大: 幅 1,600 dp 以上
windowClasses.png

ディスプレイの幅に基づくさまざまなウィンドウ サイズクラス。

非常に大きな画面では、タブレットの拡張レイアウトを単に拡大するだけでは、最適なユーザー エクスペリエンスが得られないことがあります。たとえば、メール クライアントは、Expanded ウィンドウ サイズクラスで 2 つのペイン(メールボックスとメッセージ)を快適に表示できます。しかし、特大のデスクトップ モニターでは、メール クライアントは 3 つまたは 4 つのペイン(メールボックス、メッセージ リスト、メッセージの全内容、カレンダー / タスクパネルなど)をすべて一度に表示できます。

プロジェクトに新しいウィンドウ サイズクラスを含めるには、WindowSizeClass.BREAKPOINTS_V1 ではなく WindowSizeClass.BREAKPOINTS_V2 セットから関数を呼び出します。

val currentWindowMetrics =
    WindowMetricsCalculator.getOrCreate()
    .computeCurrentWindowMetrics(LocalContext.current)

val sizeClass = WindowSizeClass.BREAKPOINTS_V2
    .computeWindowSizeClass(currentWindowMetrics)

アプリに少なくともそれだけのスペースがあることを確認したら、適切なレイアウトを適用します。

if(sizeClass.isWidthAtLeastBreakpoint(
    WindowSizeClass.WIDTH_DP_LARGE_LOWER_BOUND)){
    ...
	// Window is at least 1200 dp wide.
}

Jetpack Navigation 3 でアダプティブ レイアウトを構築する

Navigation 3 は、Jetpack コレクションに新たに追加された最新の機能です。Navigation 3 は、Compose と連携するように設計された強力なナビゲーション ライブラリで、最初の安定版リリースが公開されたばかりです。

Navigation 3 は、複数のデスティネーションを同時に表示し、シームレス切り替えを可能にすることで、アダプティブ レイアウトを構築するための優れたツールでもあります。

アプリの UI フローを管理するこのシステムは、シーンに基づいています。シーンは、1 つ以上の宛先を同時に表示するレイアウトです。SceneStrategy は、Scene を作成できるかどうかを判断します。SceneStrategy インスタンスを連結すると、画面サイズやデバイス設定ごとに異なるシーンを作成して表示できます。

リストと詳細や補足ペインなどの標準的な正規レイアウトの場合は、Compose Material 3 Adaptive ライブラリのシーンを使用できます(バージョン 1.3 以降で利用可能)。

また、シーンのレシピを変更するか、ゼロから作成することで、独自のカスタムシーンを簡単に作成できます。たとえば、3 つのペインを並べて表示する Scene を考えてみましょう。

class ThreePaneScene<T : Any>(
    override val key: Any,
    override val previousEntries: List<NavEntry<T>>,
    val firstEntry: NavEntry<T>,
    val secondEntry: NavEntry<T>,
    val thirdEntry: NavEntry<T>
) : Scene<T> {
    override val entries: List<NavEntry<T>> = listOf(firstEntry, secondEntry, thirdEntry)
    override val content: @Composable (() -> Unit) = {
        Row(modifier = Modifier.fillMaxSize()) {
            Column(modifier = Modifier.weight(1f)) {
                firstEntry.Content()
            }
            Column(modifier = Modifier.weight(1f)) {
                secondEntry.Content()
            }
            Column(modifier = Modifier.weight(1f)) {
                thirdEntry.Content()
            }
        }
    }

このシナリオでは、ウィンドウ幅が十分に広く、バックスタックのエントリが 3 ペインのシーンでの表示をサポートしていると宣言している場合に、3 つのペインを表示する SceneStrategy を定義できます。

class ThreePaneSceneStrategy<T : Any>(val windowSizeClass: WindowSizeClass) : SceneStrategy<T> {
    override fun SceneStrategyScope<T>.calculateScene(entries: List<NavEntry<T>>): Scene<T>? {
        if (windowSizeClass.isWidthAtLeastBreakpoint(WIDTH_DP_LARGE_LOWER_BOUND)) {
            val lastThree = entries.takeLast(3)
            if (lastThree.size == 3 && lastThree.all { it.metadata.containsKey(MULTI_PANE_KEY) }) {
                val firstEntry = lastThree[0]
                val secondEntry = lastThree[1]
                val thirdEntry = lastThree[2]


                return ThreePaneScene(
                    key = Triple(firstEntry.contentKey, secondEntry.contentKey, thirdEntry.contentKey),
                    previousEntries = entries.dropLast(3),
                    firstEntry = firstEntry,
                    secondEntry = secondEntry,
                    thirdEntry = thirdEntry
                )
            }
        }
        return null
    }
}

NavDisplay の作成時に、ThreePaneSceneStrategy を他の戦略と組み合わせて使用できます。たとえば、3 つのペインを表示するのに十分なスペースがない場合に、2 つのペインを横並びで表示する TwoPaneStrategy を追加することもできます。

val strategy = ThreePaneSceneStrategy() then TwoPaneSceneStrategy()

NavDisplay(..., 
  sceneStrategy = strategy,
  entryProvider = entryProvider { 
    entry<MyScreen>(metadata = mapOf(MULTI_PANE_KEY to true))) { ... }
    ... other entries...
  }
)

3 つまたは 2 つのペインを表示するのに十分なスペースがない場合、両方のカスタム シーン戦略が null を返します。この場合、NavDisplay は SinglePaneScene を使用して、バックスタックの最後のエントリを単一ペインに表示するようにフォールバックします。 

シーンと戦略を使用することで、1 ペイン、2 ペイン、3 ペインのレイアウトをアプリに追加できます。

adaptivepane.gif

幅広の画面で 3 ペイン ナビゲーションを表示するアダプティブ アプリ。

Navigation 3 のシーンを使用してカスタム レイアウトを作成する方法について詳しくは、ドキュメントをご覧ください。

スタンドアロンのアダプティブ レイアウト

スタンドアロン レイアウトが必要な場合は、Compose Material 3 Adaptive ライブラリを使用すると、ウィンドウ サイズクラスやデバイスの向きに基づいて、ウィンドウ構成に自動的に適応するリストと詳細やサポート ペイン レイアウトなどのアダプティブ UI を作成できます。

幸いなことに、ライブラリはすでに新しいブレークポイントで最新の状態になっています。バージョン 1.2 以降、デフォルトのペイン スキャフォールド ディレクティブ関数は、幅が Large と Extra-large のウィンドウ サイズクラスをサポートしています。

新しいブレークポイントを使用することを Gradle ビルドファイルで宣言して、オプトインするだけで済みます。

currentWindowAdaptiveInfo(supportLargeAndXLargeWidth = true)

スタートガイド

最新バージョンの Android の接続ディスプレイ機能について説明します。サポート対象のデバイスに Android 16 QPR3 をインストールし、外部モニターに接続して、今すぐアプリのテストを開始しましょう。

マルチディスプレイのサポートとウィンドウ管理に関する最新のドキュメントで、これらのベスト プラクティスの実装方法をご確認ください。

フィードバック

皆様からのフィードバックは、接続されたディスプレイのデスクトップ エクスペリエンスの改善に役立てさせていただきます。ご意見、ご要望、問題の報告は、公式フィードバック チャンネルからお送りいただけます。

Google は、ユーザーがアプリやデバイスを操作するさまざまな方法に適応する、汎用性の高いプラットフォームとして Android を構築することに尽力しています。接続ディスプレイのサポートの改善は、その方向へのもう 1 つのステップです。皆さんが構築するデスクトップ エクスペリエンスは、ユーザーに気に入っていただけると思います。


*注: この記事の執筆時点では、接続されたディスプレイは、Google Pixel 8、9、10 シリーズと、S26、Fold7、Flip7、Tab S11 を含む幅広い Samsung デバイスでサポートされています。

作成者:
続きを読む