ナビゲーション アプリを作成する

このセクションでは、ターンバイターン方式のナビゲーション アプリの機能を実装するための、ライブラリの各機能について詳しく説明します。

マニフェストでナビゲーション サポートを宣言する

ナビゲーション アプリでは、CarAppService のインテント フィルタで自動車アプリのカテゴリとして androidx.car.app.category.NAVIGATION を宣言する必要があります。

<application>
    ...
   <service
       ...
        android:name=".MyNavigationCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService" />
        <category android:name="androidx.car.app.category.NAVIGATION"/>
      </intent-filter>
    </service>
    ...
<application>

ナビゲーション インテントをサポートする

アプリに送信されるナビゲーション インテント(音声クエリを使用して Google アシスタントから取得したものを含む)をサポートするために、アプリは Session.onCreateScreenSession.onNewIntent の中で CarContext.ACTION_NAVIGATE インテントを処理する必要があります。

インテントの形式について詳しくは、CarContext.startCarApp のドキュメントをご覧ください。

ナビゲーション テンプレートにアクセスする

ナビゲーション アプリは、ナビゲーション アプリ専用に設計された以下のテンプレートにアクセスできます。これらのテンプレートはすべて、地図を描画するためにアプリがアクセスできるサーフェスを背景に表示するとともに、テンプレートごとに異なる、アプリ提供の情報を表示します。

  • NavigationTemplate: 地図を表示します。必要に応じて、アクティブなナビゲーション中に、情報メッセージ、経路案内、所要時間も表示します。
  • PlaceListNavigationTemplate: 場所のリストを表示します。これらの場所に対応するマーカーを地図上に描画できます。
  • RoutePreviewNavigationTemplate: 経路のリストを表示します。これらの経路のひとつを選択して、地図上でハイライト表示できます。

これらのテンプレートを使用してナビゲーション アプリのユーザー インターフェースを設計する方法について詳しくは、自動車向け Android アプリ ライブラリの設計ガイドラインをご覧ください。

ナビゲーション テンプレートにアクセスするには、アプリは AndroidManifest.xmlandroidx.car.app.NAVIGATION_TEMPLATES 権限を宣言する必要があります。

<uses-permission android:name="androidx.car.app.NAVIGATION_TEMPLATES"/>

地図の描画

ナビゲーション アプリは、適用するテンプレート上で地図を描画するために Surface にアクセスできます。

SurfaceContainer オブジェクトにアクセスするには、SurfaceCallback インスタンスを AppManager 自動車サービスに設定します。

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

Java

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

SurfaceCallback は、SurfaceContainer が利用可能な場合のコールバックのほか、Surface のプロパティが変更された場合の他のコールバックを提供します。

サーフェスにアクセスするには、アプリは AndroidManifest.xmlandroidx.car.app.ACCESS_SURFACE 権限を宣言する必要があります。

<uses-permission android:name="androidx.car.app.ACCESS_SURFACE"/>

地図の表示エリア

ホストは、地図上にさまざまなテンプレートのユーザー インターフェース要素を描画できます。ホストは、SurfaceCallback.onVisibleAreaChanged を呼び出すことで、遮るものがなく、ユーザーに完全に表示されることが保証されている領域を伝えます。また、変更回数を最小限に抑えるために、ホストは SurfaceCallback.onStableAreaChanged メソッドを呼び出します。この呼び出しでは現在のテンプレートに基づいて表示される最大の長方形が使用されます。

たとえば、ナビゲーション アプリが NavigationTemplate を使用していて、上部にアクション ストリップがある場合、ユーザーがしばらく画面を操作しなければアクション ストリップ自体が非表示になり、地図用のスペースが増えます。この場合、onStableAreaChangedonVisibleAreaChanged へのコールバックは同じ長方形で行われます。アクション ストリップが非表示になると、onVisibleAreaChanged のみがより大きい領域で呼び出されます。ユーザーが画面を操作すると、最初の長方形で onVisibleAreaChanged のみが再度呼び出されます。

ダークモード

条件が満たされているとホストが判断した場合、ナビゲーション アプリは、Android Auto アプリの品質に関するガイドラインの説明のとおり、適切な暗い色を使用して Surface インスタンスに地図を再描画する必要があります。

暗い地図を描くかどうかを決定するには、CarContext.isDarkMode メソッドを使用します。ダークモードのステータスが変更されるたびに、Session.onCarConfigurationChanged の呼び出しを受け取ります。

ナビゲーション アプリは、ホストに追加のナビゲーション メタデータを伝える必要があります。ホストはこの情報を使用して、車のヘッドユニットに情報を伝え、共有リソース上のナビゲーション アプリ間の競合を防ぎます。

ナビゲーション メタデータは、CarContext からアクセスできる NavigationManager 自動車サービスを通じて取得できます。

Kotlin

val navigationManager = carContext.getCarService(NavigationManager::class.java)

Java

NavigationManager navigationManager = carContext.getCarService(NavigationManager.class);

ナビゲーションの開始、終了、停止

複数のナビゲーション アプリ、経路通知、自動車クラスタデータを管理するには、ホストはナビゲーションの現在の状態を認識する必要があります。ユーザーがナビゲーションを開始したときに、アプリは NavigationManager.navigationStarted を呼び出す必要があります。同様に、ユーザーが目的地に到着したときや、ナビゲーションをキャンセルしたときなど、ナビゲーションが終了したときに、アプリは NavigationManager.navigationEnded を呼び出す必要があります。

ユーザーが操作を終了したときのみ、NavigationManager.navigationEnded を呼び出してください。たとえば、ルートの途中で経路を再計算する必要がある場合は、Trip.Builder.setLoading(true) を使用します。

状況によって、ホストは、アプリがナビゲーションを停止することを必要とする場合があります。このような場合、NavigationManager.setListener を使用してアプリが提供する NavigationManagerListener オブジェクトの stopNavigation が呼び出されます。するとアプリは、クラスタ表示、ナビゲーション通知、音声案内で、次のターンの情報の発行を停止しなければならなくなります。

ルート情報

アクティブなナビゲーション中に、アプリは NavigationManager.updateTrip を呼び出す必要があります。この呼び出しで提供される情報は、車のクラスタとヘッドアップ ディスプレイで使用されます。運転中の車によっては、一部の情報がユーザーに表示されない場合があります。たとえば、デスクトップ ヘッドユニットには、Trip に追加された Step は表示されますが、Destination 情報は表示されません。

情報がクラスタに到達しているかどうかをテストするため、簡単なクラスタ表示を行うようにデスクトップ ヘッドユニット(DHU)ツールを構成できます。次の内容の cluster.ini ファイルを作成します。

[general]
instrumentcluster = true

その後、コマンドライン パラメータを追加して DHU を呼び出すことができます。

dhu -c cluster.ini

ターンバイターン通知

頻繁に更新されるナビゲーション通知とともに、ターンバイターン(TBT)方式のナビゲーション指示を提供できます。車の画面でナビゲーション通知として処理されるようにするには、通知ビルダーで以下を行う必要があります。

  1. NotificationCompat.Builder.setOngoing メソッドを使用して、通知を進行中としてマークします。
  2. 通知のカテゴリを Notification.CATEGORY_NAVIGATION に設定します。
  3. CarAppExtender を使用して通知を拡張します。

ナビゲーション通知は車の画面下部にあるレール ウィジェットに表示されます。通知の重要度レベルが IMPORTANCE_HIGH に設定されている場合は、ヘッドアップ通知(HUN)としても表示されます。CarAppExtender.Builder.setImportance メソッドで重要度が設定されていない場合は、通知チャンネルの重要度が使用されます。

アプリは、ユーザーが HUN またはレール ウィジェットをタップしたときにアプリに送信される PendingIntentCarAppExtender で設定できます。

値を true に指定して NotificationCompat.Builder.setOnlyAlertOnce が呼び出された場合、重要度の高い通知は HUN で 1 回だけアラートを送信します。

次のスニペットは、ナビゲーション通知を作成する方法を示しています。

Kotlin

NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    ...
    .setOnlyAlertOnce(true)
    .setOngoing(true)
    .setCategory(NotificationCompat.CATEGORY_NAVIGATION)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(carScreenTitle)
            ...
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_OPEN_APP.hashCode(),
                    Intent(ACTION_OPEN_APP).setComponent(
                        ComponentName(context, MyNotificationReceiver::class.java)),
                        0))
            .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
            .build())
    .build()

Java

new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    ...
    .setOnlyAlertOnce(true)
    .setOngoing(true)
    .setCategory(NotificationCompat.CATEGORY_NAVIGATION)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(carScreenTitle)
            ...
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_OPEN_APP.hashCode(),
                    new Intent(ACTION_OPEN_APP).setComponent(
                        new ComponentName(context, MyNotificationReceiver.class)),
                        0))
            .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
            .build())
    .build();

ターンバイターン通知に関するガイドライン

ナビゲーション アプリは距離の変化に応じて TBT 通知を定期的に更新する必要があります。これにより、レール ウィジェットが更新され、通知は HUN としてのみ表示されます。アプリは CarAppExtender.Builder.setImportance メソッドで通知の重要度を設定することで、HUN の動作を制御できます。重要度を IMPORTANCE_HIGH に設定すると HUN が表示され、他の値に設定すると、レール ウィジェットの更新のみが行われます。

音声案内

車載スピーカーでナビゲーション ガイダンスを再生するには、アプリで音声フォーカスをリクエストする必要があります。AudioFocusRequest の一部として、使用量を AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE として設定します。フォーカス ゲインも AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK として設定します。

ナビゲーションのシミュレーション

アプリを Google Play ストアに送信する際に、アプリのナビゲーション機能を検証するために、アプリで NavigationManagerCallback.onAutoDriveEnabled コールバックを実装する必要があります。このコールバックが呼び出されると、ユーザーがナビゲーションを開始したときに、アプリで、選択された目的地へのナビゲーションをシミュレートする必要があります。現在の Session のライフサイクルが Lifecycle.Event.ON_DESTROY 状態になると、アプリはこのモードを終了できます。

コマンドラインから以下を実行することで、onAutoDriveEnabled の実装が呼び出されることをテストできます。

adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE

例:

adb shell dumpsys activity service androidx.car.app.samples.navigation.car.NavigationCarAppService AUTO_DRIVE

デフォルトのナビゲーション自動車アプリ

Android Auto では、デフォルトのナビゲーション自動車アプリは、ユーザーが最後に起動したナビゲーション アプリに対応します。たとえば、ユーザーがアシスタントを介してナビゲーション コマンドを呼び出した場合や、他のアプリからナビゲーションを開始するためにインテントを送信すると、このアプリがナビゲーション インテントを受信します。

ユーザーに地図の操作を許可する

自動車向けアプリの API レベル 2 以降では、NavigationTemplate で地図にズームとパンを追加することで、地図のさまざまな部分をユーザーに表示できます。

SurfaceCallback メソッド

SurfaceCallback には、NavigationTemplate に地図のインタラクティブ機能を追加するためのコールバック メソッドが 3 つあります(onScaleonScrollonFling)。 これらのコールバックとユーザーの操作との関連については、次の表をご覧ください。

操作 SurfaceCallback メソッド
ピンチ(ズーム) onScale
シングルタップ ドラッグ onScroll
シングルタップ フリング onFling
ダブルタップ onScale(テンプレート ホストによってスケーリング ファクタが決定される)
パンモードの回転ナッジ onScroll(テンプレート ホストによって距離ファクタが決定される)

マップ アクション ストリップ

NavigationTemplate では、地図に関連する操作(拡大 / 縮小、センタリング、コンパスの表示など、アプリで可能にする操作)に対応する、マップ アクション ストリップを設定できます。マップ アクション ストリップには、タスクの階層を変更することなく更新できる、アイコンのみのボタンを 4 つまで設定できます。アクション ストリップと同様に、マップ アクション ストリップはアイドル状態には非表示になり、アクティブ状態になると表示されます。

マップ インタラクティビティ コールバックを受け取るようにするには、マップ アクション ストリップに Action.PAN ボタンを追加する必要があります。アプリのマップ アクション ストリップに Action.PAN ボタンを設定しないと、SurfaceCallback メソッドからユーザー入力を取得できず、ホストで有効になっていたパンモードが終了します。ユーザーがパンボタンを押すと、ホストがパンモードに切り替わります。パンボタンはタッチスクリーンには表示されません。

パンモード

パンモードでは、ノンタップの入力デバイス(ロータリー コントローラやタッチパッドなど)からのユーザー入力が、テンプレート ホストによって適切な SurfaceCallback メソッドに変換されます。パンモードを開始または終了するユーザー操作に応答するには、NavigationTemplate BuildersetPanModeListener メソッドを使用します。ユーザーがパンモードになっている間は、他の UI コンポーネントを非表示にできます。

安定領域

安定領域は、アイドル状態とアクティブ状態の間に更新されます。アプリで速度、速度制限、道路警告などの運転関連の情報を表示させる場合は、地図上の重要な情報がマップ アクション ストリップによって遮られないように、安定領域のサイズに応じて情報が取得されるようにします。