建構導航應用程式

Stay organized with collections Save and categorize content based on your preferences.

本節詳細介紹程式庫的不同功能,您可以利用這些功能為即時路線導航應用程式實作各項功能。

在資訊清單中宣告導航支援

導航應用程式必須在 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」詳細說明文件。

存取導航範本

導航應用程式可以存取專為導航應用程式設計的以下專用範本。這些範本能在背景中顯示途徑,使應用程式可存取以繪製地圖,並會顯示其他由應用程式提供的資訊,但這些會依範本而各有不同。

如要瞭解如何運用這些範本來設計導航應用程式的使用者介面,請參閱《車輛專用 Android App Library 設計指南》。

為存取導航範本,應用程式必須在其 AndroidManifest.xml 中宣告 androidx.car.app.NAVIGATION_TEMPLATES 權限:

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

繪製地圖

導航應用程式可以存取 Surface,以在相關範本中繪製地圖。

然後可設定 SurfaceCallback 執行個體 為 AppManager 車輛服務以存取 SurfaceContainer 物件:

Kotlin

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

Java

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

Surface 屬性異動時,SurfaceCallback 就會在 SurfaceContainer 可用時提供回呼以及其他回呼。

如要存取途徑,則應用程式需在其 AndroidManifest.xml 中宣告 androidx.car.app.ACCESS_SURFACE 權限:

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

地圖可見區域

主機可在地圖上針對不同範本繪製使用者介面元素。只要呼叫 SurfaceCallback.onVisibleAreaChanged 方法,主機即可與使用者絕對可見的開放區域通訊。此外,為了盡量減少異動次數,主機也會呼叫 SurfaceCallback.onStableAreaChanged 方法及小矩形廣告,且此會依據目前範本總是顯示。

舉例來說,如果導航應用程式使用有頂端動作列的 NavigationTemplate,在使用者有一段時間並未與畫面互動後,系統就會隱藏該動作列,為地圖提供更多空間。在這種情況下,系統會使用相同矩形回呼 onStableAreaChangedonVisibleAreaChanged。隱藏操作列時,系統只會使用較大區域呼叫 onVisibleAreaChanged。如果使用者與畫面互動,系統只會使用第一個矩形呼叫 onVisibleAreaChanged

深色模式

當主機判定條件可提供擔保時,導航應用程式必須使用適當的深色顏色在 Surface 上重畫其地圖,如「Android Auto 應用程式品質指南」所述。

如要判斷是否應繪製深色地圖,您可以使用 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。此呼叫中提供的資訊將用於車輛的叢集和看路提醒顯示。視駕駛的特定車輛而定,並非所有資訊都會向使用者顯示。舉例來說,電腦版車用運算主機會顯示已新增至 TripStep,但不會顯示 Destination 資訊。

為了要測試資訊是否送達叢集,電腦版車用運算主機可以設定危險是簡易叢集顯示。請使用以下內容建立 cluster.ini 檔案:

[general]
instrumentcluster = true

然後您可以使用其他指令列參數叫用 DHU:

dhu -c cluster.ini

使用文字和/或圖示自訂 TravelEstimated

如要利用文字和/或圖示自訂預估交通時間,請使用 TravelEstimate.BuildersetTripIcon 和/或 setTripText 方法。NavigationTemplate 使用 TravelEstimate 來選擇設定文字和圖示,或是取代預估抵達時間、剩餘時間和距離。

圖 1. 使用自訂圖示和文字進行旅遊預估

下列程式碼片段使用了 TravelEstimate.BuildersetTripIconsetTripText 自訂旅遊預估的方法:

Kotlin

TravelEstimate.Builder(Distance.create(...), DateTimeWithZone.create(...))
      ...
      .setTripIcon(CarIcon.Builder(...).build())
      .setTripText(CarText.create(...))
      .build()

Java

new TravelEstimate.Builder(Distance.create(...), DateTimeWithZone.create(...))
      ...
      .setTripIcon(CarIcon.Builder(...).build())
      .setTripText(CarText.create(...))
      .build();

即時路線導航通知

即時路線 (TBT) 導航指示可透過經常更新的導航通知提供。為了在汽車螢幕上順利顯示導航通知,通知建構工具必須執行下列操作:

  1. 使用 NotificationCompat.Builder.setOngoing 方法,將通知標示為進行中。
  2. 將通知的類別設為 Notification.CATEGORY_NAVIGATION
  3. 使用 CarAppExtender 擴充通知。

導航通知會在車輛螢幕底部的邊欄小工具中顯示。如果通知的重要性等級設為 IMPORTANCE_HIGH,則也會顯示為看路提醒通知 (HUN)。如果並未使用 CarAppExtender.Builder.setImportance 方法設定重要性,系統就會使用通知管道的重要性

應用程式可設定 CarAppExtender 中的 PendingIntent,並在使用者輕觸 HUN 或邊欄小工具時傳送至應用程式。

如果使用 true 值呼叫 NotificationCompat.Builder.setOnlyAlertOnce,則重要性極高的通知只會在 HUN 中顯示一次。

下列程式碼片段說明如何建構導航通知:

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,如將其設為任何其他值,將只會更新邊欄小工具。

重新整理 PlaceListNavigationTemplate 內容

您可以啟用驅動程式,以便在瀏覽使用 PlaceListNavigationTemplate 建構的地點清單時,輕觸按鈕以重新整理內容。實作 OnContentRefreshListener 介面的 onContentRefreshRequested 方法和使用 PlaceListNavigationTemplate.Builder.setOnContentRefreshListener 設定範本的事件監聽器,以啟用清單重新整理。

下列程式碼片段說明如何在範本中設定事件監聽器:

Kotlin

PlaceListNavigationTemplate.Builder()
    ...
    .setOnContentRefreshListener {
        // Execute any desired logic
        ...
        // Then call invalidate() so onGetTemplate() is called again
        invalidate()
    }
    .build()

Java

new PlaceListNavigationTemplate.Builder()
        ...
        .setOnContentRefreshListener(() -> {
            // Execute any desired logic
            ...
            // Then call invalidate() so onGetTemplate() is called again
            invalidate();
        })
        .build();

只有在事件監聽器含有值時,重新整理按鈕才會顯示在 PlaceListNavigationTemplate 的標頭中。

當驅動程式按一下重新整理按鈕時,系統會呼叫 OnContentRefreshListener 實作的 onContentRefreshRequested 方法。在 onContentRefreshRequested 中呼叫 Screen.invalidate 方法。主機隨後會呼叫應用程式的 Screen.onGetTemplate 方法,以使用重新整理的內容擷取範本。如要進一步瞭解如何重新整理範本,請參閱「重新整理範本內容」。只要 onGetTemplate 傳回的下一個範本類型相同,系統就會計為重新整理,而不會計入範本配額。

語音導引

若要透過車輛音響播放語音導航,應用程式必須要求音訊焦點。做為 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 中,使用者最後啟動的導航程式會成為預設的車輛導航應用程式。舉例來說,當使用者透過 Google 助理叫用導航指令,或其他應用程式傳送意圖以開始導航時,應用程式就會接收導航意圖

允許使用者與地圖互動

您可以新增使用者與地圖互動的支援功能,例如縮放及平移地圖,讓使用者查看地圖上的不同部分。每個範本有最低的 Car App API 級別規定。如要瞭解要導入的範本最低層級,請參閱下表。

範本從 Car App API 級別開始支援互動功能
NavigationTemplate2
PlaceListNavigationTemplate4
RoutePreviewNavigationTemplate4
MapTemplate5

SurfaceCallback 方法

SurfaceCallback 提供多種回呼方法,讓您透過 NavigationTemplatePlaceListNavigationTemplateRoutePreviewNavigationTemplate、或 MapTemplate 範本來增加地圖互動性: onClickonScrollonScaleonFling。請參閱下表以瞭解這些回呼與使用者互動之間的關係。

互動 SurfaceCallback 方法 從 Car App API 級別開始支援
輕觸一下 onClick 5
雙指撥動 (縮放) onScale 2
單點觸控拖曳 onScroll 2
單點觸控滑動 onFling 2
輕觸兩下 onScale (由範本主機決定縮放比例係數) 2
平移模式的旋轉自動提醒 onScroll (由範本主機決定的距離係數) 2

地圖動作區域

NavigationTemplatePlaceListNavigationTemplateRoutePreviewNavigationTemplate,和 MapTemplate 可以有地圖操作列,以執行地圖相關的動作,例如:縮放大小、重新置中對齊、指南針,或任何其他應用程式可以選擇顯示的功能。地圖操作列最多可有四個純圖示按鈕,這些按鈕可重新整理,並且不影響工作深度。如同操作列,沒有進行中的活動時,閒置的地圖操作列會自動隱藏。

如要接收地圖互動回呼,您必須在地圖操作列中新增 Action.PAN 按鈕。如果應用程式忽略 Action.PAN 地圖操作列的按鈕,您將不會從 SurfaceCallback 方法收到使用者輸入內容,而且主機會結束先前已啟用的平移模式。只要點按平移按鈕,主機即進入平移模式。如果是觸控螢幕,則不會顯示平移按鈕。

平移模式

在平移模式下,使用者透過非觸控輸入裝置 (例如旋轉控制器和觸控板) 輸入的內容,會由範本主機轉譯成適當的 SurfaceCallback 方法。使用 NavigationTemplate Builder 中的 setPanModeListener 方法,可對使用者進入或結束平移模式時做出反應。使用者處於平移模式時,主機會隱藏範本中的其他 UI 元件。

穩定區域

穩定區域會在閒置和啟用狀態之間進行更新。導航應用程式應繪製合乎穩定區域大小的行車相關資訊,以便顯示速度、速限或道路警告等重要資訊,且避免遭到地圖操作列遮住。

結構定義中的導航快訊

Alert 會向駕駛人顯示重要資訊,並提供選用動作,無須離開導航畫面。為了讓駕駛人享有最佳體驗,Alert 會在 NavigationTemplate 中運作,以避免遮擋導航路徑,盡量減少駕駛人分心的情況。

Alert 僅適用於 NavigationTemplate。如要通知 NavigationTemplate 以外的使用者,請考慮使用看路提醒頭通知 (HUN),如顯示通知一節所述。

舉例來說,使用 Alert 即可:

  • 告知駕駛人與目前導航相關的更新內容,例如路況變更。
  • 詢問駕駛人與目前導航相關的更新,例如移動式測速照相機。
  • 提出即將到來的任務,並詢問司機是否要接受,例如駕駛人是否願意順路接送乘客。

在基本格式中,Alert 是由標題和 Alert 時長所組成。時間長度會以進度列顯示。您可以視需要新增字幕、圖示和最多兩個 Action

圖 1 結構定義導覽快訊

一旦顯示 Alert 後,如果駕駛人互動導致離開 NavigationTemplate,該範本並不會沿用至其他範本。 一直停留在原始的 NavigationTemplate 中,直到 Alert 逾時為止,使用者會採取動作或應用程式會關閉 Alert

設定快訊時長

選擇符合應用程式需求的 Alert 持續時長。導航 Alert 的建議時間長度為 10 秒。請參閱「車輛專用 Android 設計指南」中的指南。

建立快訊

使用 Alert.Builder 建立 Alert 執行個體。

Kotlin

Alert.Builder(
        /*alertId*/ 1,
        /*title*/ CarText.create("Hello"),
        /*durationMillis*/ 5000
    )
    // The fields below are optional
    .addAction(firstAction)
    .addAction(secondAction)
    .setSubtitle(CarText.create(...))
    .setIcon(CarIcon.APP_ICON)
    .setCallback(...)
    .build()

Java

new Alert.Builder(
        /*alertId*/ 1,
        /*title*/ CarText.create("Hello"),
        /*durationMillis*/ 5000
    )
    // The fields below are optional
    .addAction(firstAction)
    .addAction(secondAction)
    .setSubtitle(CarText.create(...))
    .setIcon(CarIcon.APP_ICON)
    .setCallback(...)
    .build();

如要監聽 Alert 的取消或關閉作業,請建立 AlertCallback 介面的實作。AlertCallback 呼叫路徑如下:

顯示快訊

如要顯示 Alert,呼叫 AppManager.showAlert,此方法可透過應用程式上的 CarContext 取得。

// Show an alert
carContext.getCarService(AppManager.class).showAlert(alert)

關閉快訊

雖然 Alert 因逾時或駕駛人互動而自動關閉,但您也可以手動關閉 Alert。例如,您希望關閉 Alert,因為其資訊已過時。如要關閉 Alert,透過 AlertalertId 呼叫 dismissAlert 方法。

// Dismiss the same alert
carContext.getCarService(AppManager.class).dismissAlert(alert.getId())

使用與目前顯示的 Alert (如有) 不符的 alertId,呼叫 dismissAlert 沒有任何作用。(不會擲回例外狀況)。