Navigasyon uygulaması oluşturma

Bu sayfada, adım adım navigasyon uygulamanızın işlevlerini uygulamak için kullanabileceğiniz Araba Uygulaması Kitaplığı'nın farklı özellikleri ayrıntılı olarak açıklanmaktadır.

Manifest dosyanızda gezinme desteğini bildirin

Navigasyon uygulamanız, CarAppService manifest dosyasının intent filtresinde androidx.car.app.category.NAVIGATION araba uygulaması kategorisini beyan etmelidir:

<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>

Gezinme amaçlarını destekleme

Çeşitli amaç biçimleri, navigasyon uygulamalarının diğer uygulamalarla (ör. önemli yer uygulamaları ve sesli asistanlar) birlikte çalışmasına olanak tanır.

Bu intent biçimlerini desteklemek için önce uygulamanızın manifestine intent filtreleri ekleyerek desteği tanımlayın. Bu amaç filtrelerinin konumu platforma bağlıdır:

  • Android Auto: Kullanıcı Android Auto'yu kullanmadığında amaç işlenirken kullanılan <activity> manifest öğesi içinde Activity.
  • Android Automotive OS: <activity> manifest öğesi içinde CarAppActivity.

Ardından, uygulamanızın Session uygulamasındaki hem onCreateScreen() hem de onNewIntent() geri çağırmalarındaki amaçları okuyup işleyin.

Gerekli amaca dayalı reklam biçimleri

NF-6 kalite şartını karşılamak için uygulamanızın gezinme amaçlarını işlemesi gerekir.

İsteğe bağlı amaç biçimleri

Uygulamanızın birlikte çalışabilirliğini daha da artırmak için aşağıdaki amaç biçimlerini de destekleyebilirsiniz:

Navigasyon şablonlarına erişme

Navigasyon uygulamaları, aşağıdaki şablonlara erişebilir. Bu şablonlar, arka planda haritanın yer aldığı bir yüzey ve aktif navigasyon sırasında adım adım yol tariflerini gösterir.

  • NavigationTemplate: Etkin gezinme sırasında isteğe bağlı bir bilgilendirme mesajı ve seyahat tahminleri gösteren bir şablon.
  • MapWithContentTemplate: Bir uygulamanın harita döşemelerini bir tür içerikle (ör. liste) oluşturmasına olanak tanıyan şablon. İçerik genellikle harita parçalarının üzerinde bir yer paylaşımı olarak oluşturulur. Harita görünür durumdadır ve sabit alanlar içeriğe göre ayarlanır.

Gezinme uygulamanızın kullanıcı arayüzünü bu şablonları kullanarak tasarlama hakkında daha fazla bilgi için Gezinme uygulamaları başlıklı makaleyi inceleyin.

Navigasyon şablonlarına erişmek için uygulamanızın androidx.car.app.NAVIGATION_TEMPLATES dosyasında androidx.car.app.NAVIGATION_TEMPLATES iznini beyan etmesi gerekir:AndroidManifest.xml

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

Harita çizmek için ek izin gerekir.

MapWithContentTemplate'e geçiş yapma

Car App API düzeyi 7'den itibaren MapTemplate, PlaceListNavigationTemplate, ve RoutePreviewNavigationTemplate kullanımdan kaldırıldı. Desteği sonlandırılan şablonlar desteklenmeye devam edecek ancak MapWithContentTemplate'ya geçiş yapmanız kesinlikle önerilir.

Bu şablonların sağladığı işlevler MapWithContentTemplate kullanılarak uygulanabilir. Örnekler için aşağıdaki snippet'lere bakın:

MapTemplate

// MapTemplate (deprecated)
val templateDeprecated = MapTemplate.Builder()
    .setPane(paneBuilder.build())
    .setActionStrip(actionStrip)
    .setHeader(header)
    .setMapController(mapController)
    .build()

// MapWithContentTemplate
val template = MapWithContentTemplate.Builder()
    .setContentTemplate(
        PaneTemplate.Builder(paneBuilder.build())
            .setHeader(header)
            .build()
    )
    .setActionStrip(actionStrip)
    .setMapController(mapController)
    .build()

PlaceListNavigationTemplate

// PlaceListNavigationTemplate (deprecated)
val templateDeprecated = PlaceListNavigationTemplate.Builder()
    .setItemList(itemListBuilder.build())
    .setHeader(header)
    .setActionStrip(actionStrip)
    .setMapActionStrip(mapActionStrip)
    .build()

// MapWithContentTemplate
val template = MapWithContentTemplate.Builder()
    .setContentTemplate(
        ListTemplate.Builder()
            .setSingleList(itemListBuilder.build())
            .setHeader(header)
            .build()
    )
    .setActionStrip(actionStrip)
    .setMapController(
        MapController.Builder()
            .setMapActionStrip(mapActionStrip)
            .build()
    )
    .build()

RoutePreviewNavigationTemplate

// RoutePreviewNavigationTemplate (deprecated)
val templateDeprecated = RoutePreviewNavigationTemplate.Builder()
    .setItemList(
        ItemList.Builder()
            .addItem(
                Row.Builder()
                    .setTitle(title)
                    .build()
            )
            .build()
    )
    .setHeader(header)
    .setNavigateAction(
        Action.Builder()
            .setTitle(actionTitle)
            .setOnClickListener { /* onClick */ }
            .build()
    )
    .setActionStrip(actionStrip)
    .setMapActionStrip(mapActionStrip)
    .build()

// MapWithContentTemplate
val template = MapWithContentTemplate.Builder()
    .setContentTemplate(
        ListTemplate.Builder()
            .setSingleList(
                ItemList.Builder()
                    .addItem(
                        Row.Builder()
                            .setTitle(title)
                            .addAction(
                                Action.Builder()
                                    .setTitle(actionTitle)
                                    .setOnClickListener { /* onClick */ }
                                    .build()
                            )
                            .build()
                    )
                    .build()
            )
            .setHeader(header)
            .build()
    )
    .setActionStrip(actionStrip)
    .setMapController(
        MapController.Builder()
            .setMapActionStrip(mapActionStrip)
            .build()
    )
    .build()

Navigasyon uygulamaları, ana makineyle ek navigasyon meta verileri paylaşmalıdır. Ana makine, bilgileri araç ana birimine bilgi sağlamak ve gezinme uygulamalarının paylaşılan kaynaklar üzerinde çakışmasını önlemek için kullanır.

Gezinme meta verileri, NavigationManager CarContext üzerinden erişilebilen araç hizmeti aracılığıyla sağlanır:

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

Navigasyonu başlatma, sonlandırma ve durdurma

Ana makinenin birden fazla navigasyon uygulamasını, yönlendirme bildirimlerini ve araç kümesi verilerini yönetebilmesi için navigasyonun mevcut durumunu bilmesi gerekir. Kullanıcı navigasyonu başlattığında NavigationManager.navigationStarted işlevini çağırın. Benzer şekilde, navigasyon sona erdiğinde (ör. kullanıcı hedefine ulaştığında veya navigasyonu iptal ettiğinde) NavigationManager.navigationEnded işlevini çağırın.

Yalnızca kullanıcı gezinmeyi bitirdiğinde NavigationManager.navigationEnded çağrısı yapın. Örneğin, bir yolculuğun ortasında rotayı yeniden hesaplamanız gerekiyorsa bunun yerine Trip.Builder.setLoading(true) simgesini kullanın.

Bazen, uygulamanızın NavigationManager.setNavigationManagerCallback aracılığıyla sağladığı NavigationManagerCallback nesnesinde gezinmeyi ve aramaları durdurmak için uygulamanın ana makineye ihtiyacı olur.onStopNavigation Uygulama daha sonra küme ekranında, navigasyon bildirimlerinde ve sesli yardımda bir sonraki dönüşle ilgili bilgi vermeyi durdurmalıdır.

Seyahat bilgilerini güncelleme

Etkin navigasyon sırasında arama yapın NavigationManager.updateTrip. Bu aramada verilen bilgiler, aracın gösterge grubu ve uyarı ekranları tarafından kullanılabilir. Kullanılan araca bağlı olarak, tüm bilgiler kullanıcıya gösterilmeyebilir. Örneğin, masaüstü baş birimi (DHU), Step öğesini Trip öğesine eklenmiş olarak gösterir ancak Destination bilgilerini göstermez.

Küme ekranına çizim yapma

En etkileyici kullanıcı deneyimini sunmak için aracın gösterge panelinde temel meta verileri göstermenin ötesine geçmek isteyebilirsiniz. Car App API düzeyi 6'dan itibaren navigasyon uygulamaları, kendi içeriklerini doğrudan gösterge grubu ekranında (desteklenen araçlarda) aşağıdaki sınırlamalarla birlikte oluşturma seçeneğine sahiptir:

  • Küme görüntüleme API'si, giriş denetimlerini desteklemez.
  • Araba uygulaması kalite yönergesi NF-9: Gösterge ekranında yalnızca harita döşemeleri gösterilmelidir. Etkin bir rota, isteğe bağlı olarak bu kutucuklarda gösterilebilir.
  • Küme görüntüleme API'si yalnızca NavigationTemplate
    • Ana ekranların aksine, küme ekranlarında adım adım yol tarifleri, tahmini varış zamanı kartları ve işlemler gibi tüm NavigationTemplate kullanıcı arayüzü öğeleri tutarlı bir şekilde gösterilmeyebilir. Harita döşemeleri, tutarlı bir şekilde gösterilen tek kullanıcı arayüzü öğesidir.

Küme Desteğini Bildirme

Barındıran uygulamanın, uygulamanızın küme ekranlarında oluşturmayı desteklediğini bilmesi için androidx.car.app.category.FEATURE_CLUSTER <category> öğesini CarAppService'nizin <intent-filter> bölümüne aşağıdaki snippet'te gösterildiği gibi eklemeniz gerekir:

<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"/>
        <category android:name="androidx.car.app.category.FEATURE_CLUSTER"/>
      </intent-filter>
    </service>
    ...
</application>

Yaşam Döngüsü ve Durum Yönetimi

API düzeyi 6'dan itibaren araba uygulaması yaşam döngüsü akışı aynı kalır ancak artık CarAppService::onCreateSession, oluşturulan Session hakkında ek bilgi sağlayan SessionInfo türünde bir parametre alır (ör. ekran türü ve desteklenen şablonlar kümesi).

Uygulamalar, hem küme hem de ana ekranı işlemek için aynı Session sınıfını kullanabilir veya her ekrandaki davranışı özelleştirmek için ekrana özel Sessions oluşturabilir (aşağıdaki snippet'te gösterildiği gibi).

override fun onCreateSession(sessionInfo: SessionInfo): Session {
    return if (sessionInfo.displayType == SessionInfo.DISPLAY_TYPE_CLUSTER) {
        ClusterSession()
    } else {
        MainDisplaySession()
    }
}

Küme ekranının ne zaman veya sağlanıp sağlanmayacağı konusunda garanti verilmez. Ayrıca, kümenin Session tek Session olması da mümkündür (ör. kullanıcı, uygulamanız aktif olarak gezinirken ana ekranı başka bir uygulamayla değiştirmiştir). "Standart" sözleşmeye göre uygulama, küme ekranının kontrolünü yalnızca NavigationManager::navigationStarted çağrıldıktan sonra kazanır. Ancak, etkin bir gezinme işlemi gerçekleşmezken uygulamaya küme ekranı sağlanabilir veya küme ekranı hiç sağlanmayabilir. Uygulamanızın, harita döşemelerinin boşta kalma durumunu oluşturarak bu senaryoları işlemesi gerekir.

Ana makine, her Session için ayrı bağlayıcı ve CarContext örnekleri oluşturur. Bu, ScreenManager::push veya Screen::invalidate gibi yöntemler kullanılırken yalnızca çağrıldıkları Session öğesinin etkilendiği anlamına gelir. Uygulamalar, Session iletişimi gerekiyorsa bu örnekler arasında kendi iletişim kanallarını oluşturmalıdır (ör. yayınlar, paylaşılan tekil örnek veya başka bir şey kullanarak).

Küme Desteğini Test Etme

Uygulamanızı hem Android Auto hem de Android Automotive OS'te test edebilirsiniz. Android Auto'da bu işlem, masaüstü ana birimini ikincil bir küme ekranını taklit edecek şekilde yapılandırarak yapılır. Android Automotive OS'te API düzeyi 30 ve sonraki sürümler için genel sistem görüntüleri, bir küme ekranını taklit eder.

TravelEstimate'i metin veya simgeyle özelleştirme

Seyahat tahminini metin, simge veya her ikisiyle de özelleştirmek için TravelEstimate.Builder sınıfının setTripIcon veya setTripText yöntemlerini kullanın. NavigationTemplate, tahmini varış zamanı, kalan süre ve kalan mesafenin yanında veya yerine isteğe bağlı olarak metin ve simgeler ayarlamak için TravelEstimate kullanır.

Şekil 1. Özel simge ve metin içeren seyahat tahmini.

Aşağıdaki snippet, seyahat tahminini özelleştirmek için setTripIcon ve setTripText kullanır:

TravelEstimate.Builder(
    Distance.create(350.0, Distance.UNIT_METERS),
    arrivalTimeAtDestination
)
    .setTripIcon(
        CarIcon.Builder(
            IconCompat.createWithResource(carContext, R.drawable.ic_garage)
        ).build()
    )
    .setTripText(CarText.create("Custom Text"))
    .build()

Adım adım bildirimler sağlama

Sık sık güncellenen bir navigasyon bildirimi kullanarak adım adım (TBT) navigasyon talimatları sağlar. Araba ekranında gezinme bildirimi olarak değerlendirilmesi için bildiriminizi oluşturan öğe aşağıdakileri yapmalıdır:

  1. NotificationCompat.Builder.setOngoing yöntemiyle bildirimi devam ediyor olarak işaretleyin.
  2. Bildirimin kategorisini Notification.CATEGORY_NAVIGATION olarak ayarlayın.
  3. Bildirimi CarAppExtender ile uzatın.

Araba ekranının alt kısmındaki sütun widget'ında bir navigasyon bildirimi gösterilir. Bildirimin önem düzeyi IMPORTANCE_HIGH olarak ayarlanmışsa uyarı bildirimi (HUN) olarak da gösterilir. Önem düzeyi CarAppExtender.Builder.setImportance yöntemiyle ayarlanmazsa bildirim kanalının önem düzeyi kullanılır.

Uygulama, kullanıcı HUN'a veya ray widget'ına dokunduğunda uygulamaya gönderilen PendingIntent içinde CarAppExtender ayarlayabilir.

NotificationCompat.Builder.setOnlyAlertOnce true değeriyle çağrılırsa yüksek öncelikli bildirim, HUN'da yalnızca bir kez uyarır.

Aşağıdaki snippet'te, gezinme bildirimi oluşturma işlemi gösterilmektedir:

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)
                    ),
                    PendingIntent.FLAG_IMMUTABLE
                )
            )
            .setImportance(NotificationManagerCompat.IMPORTANCE_HIGH)
            .build()
    )
    .build()

Mesafe değişiklikleri için TBT bildirimini düzenli olarak güncelleyin. Bu işlem, ray widget'ını günceller ve bildirimi yalnızca HUN olarak gösterir. CarAppExtender.Builder.setImportance ile bildirimin önem derecesini ayarlayarak HUN davranışını kontrol edebilirsiniz. Önemi IMPORTANCE_HIGH olarak ayarlamak bir HUN gösterir. Başka bir değere ayarladığınızda yalnızca reklam sütunu widget'ı güncellenir.

PlaceListNavigationTemplate içeriğini yenileme

Sürücüler, PlaceListNavigationTemplate ile oluşturulmuş yer listelerine göz atarken tek bir düğmeye dokunarak içeriği yenileyebilir. Liste yenilemeyi etkinleştirmek için OnContentRefreshListener arayüzünün onContentRefreshRequested yöntemini uygulayın ve PlaceListNavigationTemplate.Builder.setOnContentRefreshListener ile şablonda dinleyiciyi ayarlayın.

Aşağıdaki snippet'te, şablonda dinleyicinin nasıl ayarlanacağı gösterilmektedir:

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

Yenileme düğmesi yalnızca dinleyicinin değeri varsa PlaceListNavigationTemplate üstbilgisinde gösterilir.

Kullanıcı yenileme düğmesini tıkladığında, onContentRefreshRequested uygulamanızın OnContentRefreshListener yöntemi çağrılır. onContentRefreshRequested içinde Screen.invalidate yöntemini çağırın. Ardından, düzenleyen, yenilenen içeriklerle şablonu almak için uygulamanızın Screen.onGetTemplate yöntemini tekrar çağırır. Şablonları yenileme hakkında daha fazla bilgi için Şablon içeriklerini yenileme başlıklı makaleyi inceleyin. onGetTemplate tarafından döndürülen sonraki şablon aynı türde olduğu sürece yenileme olarak kabul edilir ve şablon kotasına dahil edilmez.

Sesli rehberlik sağlama

Navigasyon talimatlarını arabanın hoparlörlerinden çalmak için uygulamanızın ses odağı istemesi gerekir. AudioFocusRequest planınız kapsamında, kullanımı AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE olarak ayarlayın. Ayrıca, odak kazancını AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK olarak ayarlayın.

Gezinmeyi simüle etme

Uygulamanızı Google Play Store'a gönderdiğinizde uygulamanızın gezinme işlevini doğrulamak için uygulamanızda NavigationManagerCallback.onAutoDriveEnabled geri çağırma işlevi uygulanmalıdır. Bu geri çağırma işlevi çağrıldığında, kullanıcı gezinmeye başladığında uygulamanız seçilen hedefe gezinmeyi simüle etmelidir. Uygulamanız, mevcut Session yaşam döngüsü Lifecycle.Event.ON_DESTROY durumuna ulaştığında bu moddan çıkabilir.

onAutoDriveEnabled uygulamanızın çağrıldığını test etmek için komut satırından aşağıdakileri çalıştırın:

adb shell dumpsys activity service CAR_APP_SERVICE_NAME AUTO_DRIVE

Bu durum aşağıdaki örnekte gösterilmektedir:

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

Varsayılan navigasyon araba uygulaması

Android Auto'da varsayılan navigasyon araba uygulaması, kullanıcının başlattığı son navigasyon uygulamasıdır. Kullanıcı, Asistan üzerinden gezinme komutları verdiğinde veya başka bir uygulama gezinmeyi başlatmak için bir amaç gönderdiğinde varsayılan uygulama gezinme amaçlarını alır.

Bağlama duyarlı gezinme uyarılarını görüntüleme

Alert, sürücüye önemli bilgileri gösterir. Bu bilgilerde, gezinme ekranının bağlamından ayrılmadan isteğe bağlı işlemler yapılabilir. Sürücüye en iyi deneyimi sunmak için, Alert, navigasyon rotasının engellenmesini önlemek ve sürücünün dikkatinin dağılmasını en aza indirmek amacıyla NavigationTemplate içinde çalışır.

Alert yalnızca NavigationTemplate içinde kullanılabilir. Kullanıcıyı NavigationTemplate dışında bilgilendirmek için Bildirimleri görüntüleme bölümünde açıklandığı gibi bir uyarı bildirimi (HUN) kullanabilirsiniz.

Örneğin, Alert simgesini kullanarak:

  • Sürücüyü, mevcut navigasyonla ilgili bir güncelleme (ör. trafik koşullarındaki değişiklik) hakkında bilgilendirin.
  • Sürücüye mevcut navigasyonla ilgili bir güncelleme (ör. hız tuzağı olup olmadığı) sorun.
  • Yaklaşan bir görevi önerin ve sürücünün bunu kabul edip etmeyeceğini sorun. Örneğin, sürücünün yol üzerinde birini alıp almayacağını sorun.

Temel biçiminde bir Alert, başlık ve Alert süre süresinden oluşur. Süre, ilerleme çubuğuyla gösterilir. İsteğe bağlı olarak, altyazı, simge ve en fazla iki Action nesne ekleyebilirsiniz.

Şekil 2. Bağlam içi gezinme uyarısı.

Bir Alert gösterildikten sonra, sürücü etkileşimi NavigationTemplate'den ayrılmayla sonuçlanırsa başka bir şablona aktarılmaz. Alert zaman aşımına uğrayana, kullanıcı bir işlem yapana veya uygulama Alert'ı kapatana kadar orijinal NavigationTemplate'da kalır.

Bir uyarı oluştur

Alert.Builder kullanarak Alert örneği oluşturma:

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

Alert iptal veya kapatma işlemlerini dinlemek istiyorsanız AlertCallback arayüzünün bir uygulamasını oluşturun. AlertCallback arama yolları şunlardır:

Uyarı süresini yapılandırma

Uygulamanızın ihtiyaçlarına uygun bir Alert süresi seçin. Bir gezinme Alert için önerilen süre 10 saniyedir. Daha fazla bilgi için Navigasyon uyarıları başlıklı makaleyi inceleyin.

Uyarı gösterme

Alert göstermek için uygulamanızın CarContext üzerinden kullanılabilen AppManager.showAlert yöntemini çağırın.

carContext.getCarService(AppManager::class.java).showAlert(alert)

  • Hâlihazırda gösterilen Alert kimliğiyle aynı alertId değerine sahip bir Alert ile showAlert çağrısı yapıldığında hiçbir işlem yapılmaz. Alert güncellenmiyor. Bir Alert öğesini güncellemek için yeni bir alertId ile yeniden oluşturmanız gerekir.
  • showAlert işlevini, halihazırda gösterilen Alert ile farklı bir alertId değerine sahip Alert ile çağırmak, gösterilen Alert uyarısını kapatır.

Uyarıyı kapatma

Alert, zaman aşımı veya sürücü etkileşimi nedeniyle otomatik olarak kapatılırken bilgileri güncelliğini yitirirse Alert'yi manuel olarak da kapatabilirsiniz. Bir Alert öğesini kapatmak için dismissAlert yöntemini Alert öğesinin alertId ile çağırın.

carContext.getCarService(AppManager::class.java).dismissAlert(alert.id)

Zaten görüntülenen Alert ile eşleşmeyen bir alertId ile dismissAlert işlevini çağırmak hiçbir şey yapmaz. İstisna oluşturmaz.