إنشاء تطبيق للتنقّل

توضّح هذه الصفحة بالتفصيل الميزات المختلفة لـ "مكتبة تطبيقات السيارات" التي يمكنك استخدامها لتطبيق وظائف تطبيق التنقّل بالاتّجاهات.

تحديد إمكانية التنقّل في بيان التطبيق

يجب أن يُفصح تطبيق التنقّل عن androidx.car.app.category.NAVIGATION فئة تطبيقات السيارات في فلتر الأهداف الخاص بنشاط CarAppService:

<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" باستخدام طلب بحث صوتي، يجب أن يعالج تطبيقك طلبات التنقّل CarContext.ACTION_NAVIGATE في Session.onCreateScreen وSession.onNewIntent.

اطّلِع على المستندات حول CarContext.startCarApp للحصول على تفاصيل حول تنسيق النية.

الوصول إلى نماذج التنقّل

يمكن لتطبيقات التنقّل الوصول إلى النماذج التالية التي تعرض سطحًا في الخلفية مع الخريطة، واتجاهات التفصيل المفصّل أثناء التنقّل النشط.

  • NavigationTemplate: يتم أيضًا عرض رسالة معلوماتية اختيارية وتقديرات للسفر أثناء التنقّل النشط.
  • MapWithContentTemplate: نموذج يسمح للتطبيق بعرض مربّعات الخريطة مع نوع من المحتوى (مثل قائمة). يتم عادةً عرض المحتوى كطبقة فوق ملفّات ‎bathered الخريطة، مع ظهور الخريطة وتعديل المناطق الثابتة لتتلاءم مع المحتوى.

لمزيد من التفاصيل حول كيفية تصميم واجهة مستخدِم تطبيق التنقّل باستخدام هذه النماذج، يُرجى الاطّلاع على تطبيقات التنقّل.

للوصول إلى نماذج التنقّل، يجب أن يُعلن تطبيقك عن إذن androidx.car.app.NAVIGATION_TEMPLATES في ملف AndroidManifest.xml:

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

يجب الحصول على إذن إضافي لرسم الخرائط.

نقل البيانات إلى MapWithContentTemplate

اعتبارًا من المستوى 7 من Car App API، تم إيقاف MapTemplate، PlaceListNavigationTemplate، وRoutePreviewNavigationTemplate نهائيًا. سيستمر توفّر النماذج المتوقّفة نهائيًا، ولكن ننصح بشدة بالانتقال إلى MapWithContentTemplate.

يمكن تنفيذ الوظائف التي تقدّمها هذه النماذج باستخدام MapWithContentTemplate. راجِع المقتطفات التالية للحصول على أمثلة:

MapTemplate

Kotlin

// MapTemplate (deprecated)
val template = 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()

Java

// MapTemplate (deprecated)
MapTemplate template = new MapTemplate.Builder()
    .setPane(paneBuilder.build())
    .setActionStrip(actionStrip)
    .setHeader(header)
    .setMapController(mapController)
    .build();

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

PlaceListNavigationTemplate

Kotlin

// PlaceListNavigationTemplate (deprecated)
val template = 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()

Java

// PlaceListNavigationTemplate (deprecated)
PlaceListNavigationTemplate template = new PlaceListNavigationTemplate.Builder()
    .setItemList(itemListBuilder.build())
    .setHeader(header)
    .setActionStrip(actionStrip)
    .setMapActionStrip(mapActionStrip)
    .build();

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

RoutePreviewNavigationTemplate

Kotlin

// RoutePreviewNavigationTemplate (deprecated)
val template = RoutePreviewNavigationTemplate.Builder()
    .setItemList(
        ItemList.Builder()
            .addItem(
                Row.Builder()
                    .setTitle(title)
                    .build())
            .build())
    .setHeader(header)
    .setNavigateAction(
        Action.Builder()
            .setTitle(actionTitle)
            .setOnClickListener { ... }
            .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 { ... }
                                    .build())
                            .build())
                    .build())
            .setHeader(header)
            .build())
    .setActionStrip(actionStrip)
    .setMapController(
        MapController.Builder()
            .setMapActionStrip(mapActionStrip)
            .build())
    .build()

Java

// RoutePreviewNavigationTemplate (deprecated)
RoutePreviewNavigationTemplate template = new RoutePreviewNavigationTemplate.Builder()
    .setItemList(new ItemList.Builder()
        .addItem(new Row.Builder()
            .setTitle(title))
            .build())
        .build())
    .setHeader(header)
    .setNavigateAction(new Action.Builder()
        .setTitle(actionTitle)
        .setOnClickListener(() -> { ... })
        .build())
    .setActionStrip(actionStrip)
    .setMapActionStrip(mapActionStrip)
    .build();

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

يجب أن ترسل تطبيقات التنقّل بيانات وصفية إضافية عن التنقّل إلى المضيف. يستخدم المضيف المعلومات لتقديم معلومات إلى الوحدة الرئيسية للسيارة ولمنع تطبيقات التنقّل من التعارض بشأن الموارد المشتركة.

يتم تقديم البيانات الوصفية للتنقّل من خلال NavigationManager خدمة السيارات التي يمكن الوصول إليها من CarContext:

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) بدلاً من ذلك.

في بعض الأحيان، يحتاج المضيف إلى تطبيق لإيقاف التنقّل وطلبات onStopNavigation في NavigationManagerCallback عنصر يقدّمه تطبيقك من خلال NavigationManager.setNavigationManagerCallback. من المفترض أن يتوقف التطبيق بعد ذلك عن عرض معلومات المنعطف التالي في شاشة الشاشة المُجمَّعة، وإرسال إشعارات التنقّل والإرشادات الصوتية.

تعديل معلومات الرحلة

أثناء التنقّل النشط، اضغط على رمز المكالمة NavigationManager.updateTrip. يمكن أن تستخدم مجموعة الأدوات في المركبة وشاشة العرض الرأسية (HUD) المعلومات المقدَّمة في هذه المكالمة. استنادًا إلى المركبة المحدّدة التي يتم قيادتها، لا يتم عرض كل المعلومات للمستخدم. على سبيل المثال، تعرِض وحدة Desktop Head Unit (DHU) Step المُضافة إلى Trip، ولكنّها لا تعرِض معلومات Destination.

الرسم على شاشة العرض المُجمَّعة

لتوفير تجربة المستخدم الأكثر تشويقًا، ننصحك بتقديم مزيد من المعلومات بدلاً من عرض البيانات الوصفية الأساسية على شاشة لوحة بيانات المركبة. بدءًا من المستوى 6 من Car App API، تتوفّر لتطبيقات التنقّل إمكانية عرض المحتوى الخاص بها مباشرةً على شاشة مجموعة العدادات (في المركبات المتوافقة)، مع مراعاة القيود التالية:

  • لا تتيح واجهة برمجة التطبيقات لعرض المجموعات عناصر التحكّم في الإدخال.
  • إرشادات جودة تطبيقات السيارات NF-9: يجب أن تعرض شاشة التراكب فقط مربّعات الخريطة. يمكن عرض مسار تنقّل نشط اختياريًا على هذه المربّعات.
  • لا تتيح واجهة برمجة التطبيقات لعرض المجموعات استخدام سوى NavigationTemplate
    • على عكس الشاشات الرئيسية، قد لا تعرض شاشات المجموعات بشكلٍ منتظم كل NavigationTemplate عناصر واجهة المستخدم، مثل تعليمات التنقّل خطوة بخطوة وبطاقات وقت الوصول المُقدَّر والإجراءات. وحدات البطاقة هي عنصر واجهة المستخدِم الوحيد الذي يظهر بشكلٍ منتظم.

الإعلان عن توفّر ميزة "المجموعات"

لإعلام التطبيق المضيف بأنّ تطبيقك متوافق مع عرض المحتوى على شاشة التجمع، يجب إضافة عنصر androidx.car.app.category.FEATURE_CLUSTER <category> إلى <intent-filter> في CarAppService كما هو موضّح في المقتطف التالي:

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

إدارة دورة الحياة والحالة

بدءًا من المستوى 6 من واجهة برمجة التطبيقات، يظلّ مسار دورة حياة تطبيق السيارة كما هو، ولكن يأخذ CarAppService::onCreateSession الآن مَعلمة من نوع SessionInfo تقدّم معلومات إضافية عن Session الذي يتم إنشاؤه (أي نوع الشاشة ومجموعة النماذج المتوافقة).

تتوفّر للتطبيقات خيارات إما استخدام فئة Session نفسها للتعامل مع كل من الشاشة المتعدّدة وشاشة العرض الرئيسية، أو إنشاء Sessions خاص بالشاشة لتخصيص السلوك على كل شاشة (كما هو موضّح في المقتطف التالي).

Kotlin

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

Java

@Override
@NonNull
public Session onCreateSession(@NonNull SessionInfo sessionInfo) {
  if (sessionInfo.getDisplayType() == SessionInfo.DISPLAY_TYPE_CLUSTER) {
    return new ClusterSession();
  } else {
    return new MainDisplaySession();
  }
}

لا تتوفّر أي ضمانات بشأن وقت عرض المجموعة أو ما إذا كان سيتم عرضها، ومن الممكن أيضًا أن تكون المجموعة Session هي Session الوحيدة (مثل استرجاع المستخدم للشاشة الرئيسية من تطبيق آخر أثناء تنقّل تطبيقك بنشاط). تقضي الاتفاقية "العادية" بأن يحصل التطبيق على التحكّم في عرض المجموعة فقط بعد استدعاء NavigationManager::navigationStarted. ومع ذلك، من الممكن أن يحصل التطبيق على شاشة عرض المجموعة بدون أن يتم إجراء عملية تنقّل نشطة، أو أن لا يحصل على شاشة عرض المجموعة مطلقًا. على تطبيقك التعامل مع هذه السيناريوهات من خلال عرض حالة "الخمول" في تطبيقك لشرائح الخريطة.

ينشئ المضيف مثيلَين من "أداة الربط" وCarContext منفصلَين لكل Session. ويعني ذلك أنّه عند استخدام الطرق مثل ScreenManager::push أو Screen::invalidate، لا يتأثّر سوى Session الذي يتم استدعاؤها منه. على التطبيقات إنشاء قنوات تواصل خاصة بها بين هذه المثيلات إذا كان من الضروري التواصل بين التطبيقاتSession (على سبيل المثال، باستخدام البث أو عنصر فريد مشترَك أو غيرها).

دعم اختبار المجموعة

يمكنك اختبار عملية التنفيذ على كل من Android Auto وAndroid Automotive. بالنسبة إلى Android Auto، يتم ذلك من خلال ضبط وحدة الرأس المكتبية لمحاكاة شاشة مجموعة العدادات الثانوية. بالنسبة إلى نظام التشغيل Android Automotive، تحاكي صور النظام العامة للمستوى 30 من واجهة برمجة التطبيقات أو الإصدارات الأحدث شاشة مجموعة المقاييس.

تخصيص "تقدير وقت التنقّل" باستخدام نص أو رمز

لتخصيص وقت التنقّل المقدَّر باستخدام نص أو رمز أو كليهما، استخدِم أسلوبَي setTripIcon أو setTripText في فئة TravelEstimate.Builder. يستخدم رمز NavigationTemplate رمز TravelEstimate لتحديد النص والرموز اختياريًا بجانب أو بدلاً من الوقت المُقدَّر للوصول والوقت المتبقّي والمسافة المتبقّية.

الشكل 1. تقدير وقت التنقّل مع رمز ونص مخصّصَين

يستخدم المقتطف التالي setTripIcon وsetTripText لتخصيص تقدير التنقّل:

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();

تقديم إشعارات بالاتّجاهات

يجب تقديم تعليمات التنقّل باتّجاهات مفصّلة باستخدام إشعار تنقّل يتم تعديله باستمرار. لكي يتم التعامل مع الإشعار على أنّه إشعار توجيه في شاشة السيارة، على منشئ الإشعار تنفيذ الخطوات التالية:

  1. ضَع علامة على الإشعار بأنّه جارٍ باستخدام الأسلوب NotificationCompat.Builder.setOngoing.
  2. اضبط فئة الإشعار على Notification.CATEGORY_NAVIGATION.
  3. وسِّع الإشعار باستخدام رمز CarAppExtender.

يظهر إشعار التنقل في تطبيق مصغّر شريط التنقل في أسفل شاشة السيارة. إذا تم ضبط مستوى أهمية الإشعار على IMPORTANCE_HIGH، يتم عرضه أيضًا كإشعار تنبيه (HUN). إذا لم يتم ضبط الأهمية باستخدام الوسيطة CarAppExtender.Builder.setImportance ، يتم استخدام أهمية قناة الإشعارات.

يمكن للتطبيق ضبط PendingIntent في ملف CarAppExtender الذي يتم إرساله إلى التطبيق عندما ينقر المستخدم على رمز HUN أو تطبيق مصغّر للشريط الجانبي.

إذا تمّت دعوة NotificationCompat.Builder.setOnlyAlertOnce بقيمة true، يتمّ إرسال تنبيه بشأن إشعار مهم للغاية مرّة واحدة فقط في 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 بانتظام عند حدوث تغييرات في المسافة، ما يؤدي إلى تعديل التطبيق المصغّر للسكك الحديدية، ولا تعرض الإشعار إلا كإشعار بوقت الوصول المقدَّر. يمكنك التحكّم في سلوك ميزة "التحدّث أثناء القيادة" من خلال ضبط أهمية الإشعار باستخدام رمز CarAppExtender.Builder.setImportance. يؤدي ضبط الأهمية على IMPORTANCE_HIGH إلى عرض رمز HUN. يؤدي ضبط it على أي قيمة أخرى إلى تعديل التطبيق المصغّر للشريط فقط.

إعادة تحميل محتوى PlaceListNavigationTemplate

يمكنك السماح للسائقين بتحديث المحتوى بنقرة زر أثناء تصفّح قوائم الأماكن التي تم إنشاؤها باستخدام PlaceListNavigationTemplate. لتفعيل إعادة تحميل القائمة، نفِّذ أسلوب onContentRefreshRequested واجهة OnContentRefreshListener واستخدِم 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 إلا إذا كان لدى المستمع قيمة.

عندما ينقر المستخدم على زرّ إعادة التحميل، يتمّ استدعاء أسلوب onContentRefreshRequested لتنفيذ OnContentRefreshListener. ضمن 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" أو عندما يرسل تطبيق آخرنية لبدء التنقّل.

عرض تنبيهات التنقّل في السياق

Alert يعرض معلومات مهمة للسائق مع إجراءات اختيارية&dash;بدون مغادرة سياق شاشة التنقّل. لتوفير أفضل تجربة للسائق، يعمل Alert ضمن NavigationTemplate لتجنُّب حجب مسار التنقّل والحدّ من تشتيت انتباه السائق.

لا يتوفّر Alert إلا في NavigationTemplate. لإشعار المستخدم خارج NavigationTemplate، ننصح باستخدام إشعار تنبيه (HUN)، كما هو موضّح في عرض الإشعارات.

على سبيل المثال، يمكنك استخدام Alert لإجراء ما يلي:

  • إبلاغ السائق بأي تعديل ذي صلة بالاتّجاه الحالي، مثل تغيُّر في ظروف حركة المرور
  • اطلب من السائق تقديم معلومات جديدة حول المسار الحالي، مثل وجود فخّ للسرعة.
  • يمكنك اقتراح مهمة قادمة وسؤال السائق عما إذا كان يقبلها، مثل ما إذا كان السائق مستعدًا لاصطحاب شخص ما في طريقه.

في شكله الأساسي، يتألّف Alert من عنوان وAlert مدة. يتم تمثيل مدة البث بشريط تقدّم. يمكنك اختياريًا إضافة عنوان فرعي ورمز وما يصل إلى عنصرين Action.

الشكل 2. تنبيه بشأن التنقل في السياق

بعد عرض Alert، لا يتم نقله إلى نموذج آخر إذا أدّى تفاعل السائق إلى مغادرة NavigationTemplate. ويبقى في NavigationTemplate الأصلي إلى أن تنتهي مهلة Alert أو ينفّذ المستخدم إجراءً أو يغلق التطبيق Alert.

إنشاء تنبيه

استخدِم 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 تلائم احتياجات تطبيقك. المدة المُقترَحة للانتقال Alert هي 10 ثوانٍ. يُرجى الاطّلاع على تنبيهات التنقّل لمزيد من المعلومات.

عرض تنبيه

لعرض Alert، استخدِم الإجراء AppManager.showAlert المتاح من خلال CarContext في تطبيقك.

// Show an alert
carContext.getCarService(AppManager.class).showAlert(alert)
  • لن يؤدي الاتصال بـ showAlert باستخدام Alert يحتوي على alertId يطابق معرّف Alert المعروض حاليًا إلى أي نتيجة. لا يتم تعديل Alert. لتعديل Alert، عليك إعادة إنشائه باستخدام alertId جديد.
  • يؤدي الاتصال بـ showAlert باستخدام Alert يحتوي على alertId مختلف عن Alert المعروض حاليًا إلى إغلاق alertId المعروض حاليًا.Alert

إغلاق تنبيه

على الرغم من أنّه يتم تلقائيًا إغلاق Alert بسبب انتهاء مهلة أو تفاعل السائق، يمكنك أيضًا إغلاق Alert يدويًا، مثلاً إذا أصبحت معلوماته قديمة. لإغلاق Alert، استخدِم الأسلوب dismissAlert مع alertId Alert.

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

لن يؤدي الاتصال بـ dismissAlert باستخدام alertId لا يتطابق معAlert المعروض حاليًا إلى أيّ إجراء. ولا يؤدي ذلك إلى طرح استثناء.