تتيح لك مكتبة تطبيقات Android للسيارات استخدام تطبيقات الملاحة أو نقاط الاهتمام أو إنترنت الأشياء أو الطقس في السيارة. ويتم ذلك من خلال توفير مجموعة من النماذج المصمَّمة لتلبية معايير تشتيت انتباه السائق، والاهتمام بالتفاصيل، مثل تنوّع عوامل شاشة السيارة وطرق الإدخال.
يقدّم هذا الدليل نظرة عامة على الميزات والمفاهيم الرئيسية للمكتبة، كما يوضّح لك خطوات إعداد تطبيق أساسي.
قبل البدء
- راجِع صفحات تصميم مناسب لقيادة السيارات التي تتناول Car App Library
- نظرة عامة على فئة تطبيقات الملاحة والتطبيقات الأخرى ذات الصلة بالقيادة
- نظرة عامة على إنشاء التطبيقات باستخدام النماذج
- الوحدات الأساسية التي تغطي النماذج ومكوّنات النماذج
- نماذج لسير العمل توضّح أنماط تجربة المستخدم الشائعة
- متطلبات التطبيقات المستندة إلى نماذج
- راجِع المصطلحات والمفاهيم الرئيسية في القسم التالي.
- تعرَّف على واجهة مستخدم نظام Android Auto وتصميم نظام التشغيل Android Automotive.
- راجِع ملاحظات الإصدار.
- راجِع العيّنات.
المصطلحات والمفاهيم الرئيسية
- النماذج والقوالب
- يتم تمثيل واجهة المستخدم من خلال رسم بياني لعناصر النموذج التي يمكن ترتيبها معًا بطرق مختلفة، حسب ما يسمح به النموذج الذي تنتمي إليه. النماذج هي مجموعة فرعية من النماذج التي يمكن أن تعمل كعنصر جذري في تلك الرسوم البيانية. تتضمّن النماذج المعلومات التي سيتم عرضها للمستخدم في شكل نصوص وصور، بالإضافة إلى سمات لتحديد جوانب المظهر المرئي لهذه المعلومات، مثل ألوان النصوص أو أحجام الصور. يحوّل التطبيق المضيف النماذج إلى طرق عرض مصمَّمة لتلبية معايير تشتيت انتباه السائق، ويتولّى معالجة التفاصيل، مثل مجموعة عوامل شاشة السيارة وطرق الإدخال.
- استضِف أصدقاءك وعائلتك
- المضيف هو مكوّن الخلفية الذي ينفّذ الوظائف التي توفّرها واجهات برمجة التطبيقات في المكتبة، ما يتيح تشغيل تطبيقك في السيارة. تتراوح مسؤوليات المضيف بين استكشاف تطبيقك وإدارة مراحل نشاطه وتحويل نماذجك إلى طرق عرض وإرسال إشعارات إلى تطبيقك بشأن تفاعلات المستخدمين. على الأجهزة الجوّالة، يتم تنفيذ هذا المضيف من خلال Android Auto. على نظام التشغيل Android Automotive، يتم تثبيت هذا المضيف كتطبيق نظام.
- قيود النماذج
- تفرض النماذج المختلفة قيودًا على محتوى نماذجها. على سبيل المثال، تتضمّن قوالب القوائم حدودًا لعدد العناصر التي يمكن عرضها للمستخدم. تتضمّن النماذج أيضًا قيودًا على طريقة ربطها لتحديد مسار مهمة. على سبيل المثال، يمكن للتطبيق إرسال ما يصل إلى خمسة نماذج إلى حزمة الشاشة. لمزيد من التفاصيل، يُرجى الاطّلاع على قيود النماذج.
Screen
Screen
هي فئة توفّرها المكتبة وتستخدمها التطبيقات لإدارة واجهة المستخدم المعروضة للمستخدم. يحتويScreen
على دورة حياة ويوفر الآلية التي تتيح للتطبيق إرسال النموذج لعرضه عندما تكون الشاشة مرئية. يمكن أيضًا إرسال مثيلاتScreen
واستردادها من حزمةScreen
، ما يضمن التزامها بقيود تسلسل النماذج.CarAppService
CarAppService
هو فئةService
مجرّدة يجب أن ينفّذها تطبيقك ويصدّرها ليتمكّن المضيف من اكتشافها وإدارتها.CarAppService
في تطبيقك مسؤول عن التحقّق من إمكانية الوثوق باتصال المضيف باستخدامcreateHostValidator
، ثم توفير مثيلاتSession
لكل اتصال باستخدامonCreateSession
.Session
Session
هي فئة مجرّدة يجب أن ينفّذها تطبيقك وأن يعرضها باستخدامCarAppService.onCreateSession
. وهو بمثابة نقطة الدخول لعرض المعلومات على شاشة السيارة. ويحتوي على دورة حياة تحدّد الحالة الحالية لتطبيقك على شاشة السيارة، مثلاً عندما يكون تطبيقك مرئيًا أو مخفيًا.عند بدء
Session
، مثلاً عند تشغيل التطبيق للمرة الأولى، يطلب المضيف عرضScreen
الأولي باستخدام طريقةonCreateScreen
.
تثبيت "مكتبة تطبيقات السيارة"
يمكنك الاطّلاع على صفحة إصدار مكتبة Jetpack للحصول على تعليمات حول كيفية إضافة المكتبة إلى تطبيقك.
ضبط ملفات بيان التطبيق
قبل إنشاء تطبيق سيارة، عليك ضبط ملفات البيان الخاصة بتطبيقك على النحو التالي.
تعريف CarAppService
يتصل المضيف بتطبيقك من خلال عملية تنفيذ CarAppService
. عليك تعريف هذه الخدمة في ملف البيان للسماح للتطبيق المضيف باكتشاف تطبيقك والاتصال به.
عليك أيضًا الإفصاح عن فئة تطبيقك في العنصر
<category>
ضمن فلتر الأهداف الخاص بتطبيقك. اطّلِع على قائمة فئات التطبيقات المتوافقة لمعرفة القيم المسموح بها لهذا العنصر.
يوضّح مقتطف الرمز التالي كيفية تعريف خدمة تطبيق سيارة لتطبيق خاص بنقاط الاهتمام في ملف البيان:
<application>
...
<service
...
android:name=".MyCarAppService"
android:exported="true">
<intent-filter>
<action android:name="androidx.car.app.CarAppService"/>
<category android:name="androidx.car.app.category.POI"/>
</intent-filter>
</service>
...
<application>
فئات التطبيقات المتوافقة
حدِّد فئة تطبيقك من خلال إضافة قيمة واحدة أو أكثر من قيم الفئات التالية إلى فلتر الأهداف عند تحديد CarAppService
كما هو موضّح في القسم السابق:
-
androidx.car.app.category.NAVIGATION
: تطبيق يوفّر اتجاهات مفصّلة للتنقّل. اطّلِع على إنشاء تطبيقات تنقّل للسيارات. -
androidx.car.app.category.POI
: تطبيق يوفّر وظائف ذات صلة بالعثور على نقاط الاهتمام، مثل أماكن ركن السيارات ومحطات الشحن ومحطات الوقود اطّلِع على إنشاء تطبيقات خاصة بالأماكن المهمة للسيارات. androidx.car.app.category.IOT
: هو تطبيق يتيح للمستخدمين اتّخاذ إجراءات ذات صلة على الأجهزة المتصلة من داخل السيارة. اطّلِع على إنشاء تطبيقات إنترنت الأشياء للسيارات.androidx.car.app.category.WEATHER
: تطبيق يتيح للمستخدمين الاطّلاع على معلومات الطقس ذات الصلة بموقعهم الجغرافي الحالي أو على طول طريقهم. اطّلِع على إنشاء تطبيقات طقس للسيارات.-
androidx.car.app.category.MEDIA
: هو تطبيق يتيح للمستخدمين تصفّح وتشغيل الموسيقى والراديو والكتب الصوتية وغيرها من المحتوى الصوتي في السيارة. اطّلِع على إنشاء تطبيقات وسائط تستند إلى نماذج للسيارات. androidx.car.app.category.MESSAGING
: تطبيق يتيح للمستخدمين التواصل باستخدام رسائل نصية قصيرة. اطّلِع على إنشاء تجارب مراسلة مستندة إلى نماذج في Android Auto.androidx.car.app.category.CALLING
: تطبيق يتيح للمستخدمين التواصل عبر المكالمات الصوتية. اطّلِع على إنشاء تجارب اتصال لتطبيق Android Auto.
يمكنك الاطّلاع على جودة تطبيقات Android للسيارات للحصول على أوصاف تفصيلية لكل فئة ومعايير انضمام التطبيقات إليها.
تحديد اسم التطبيق ورمزه
عليك تحديد اسم ورمز للتطبيق يمكن أن يستخدمهما المضيف لتمثيل تطبيقك في واجهة مستخدم النظام.
يمكنك تحديد اسم التطبيق ورمزه المستخدَمَين لتمثيل تطبيقك باستخدام السمتَين label
وicon
ضمن CarAppService
:
...
<service
android:name=".MyCarAppService"
android:exported="true"
android:label="@string/my_app_name"
android:icon="@drawable/my_app_icon">
...
</service>
...
إذا لم يتم تحديد التصنيف أو الرمز في العنصر
<service>
، سيعود المضيف إلى القيم المحددة للعنصر
<application>
.
ضبط مظهر مخصّص
لضبط تصميم مخصّص لتطبيق السيارة، أضِف عنصر <meta-data>
في ملف البيان على النحو التالي:
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
بعد ذلك، عليك تعريف مصدر النمط لضبط السمات التالية لمظهر تطبيقك المخصّص للسيارات:
<resources> <style name="MyCarAppTheme"> <item name="carColorPrimary">@layout/my_primary_car_color</item> <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item> <item name="carColorSecondary">@layout/my_secondary_car_color</item> <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
مستوى واجهة برمجة التطبيقات لتطبيقات السيارات
تحدّد "مكتبة تطبيقات السيارات" مستويات واجهة برمجة التطبيقات الخاصة بها حتى تتمكّن من معرفة ميزات المكتبة التي يتيحها مضيف النماذج في السيارة.
لاسترداد أعلى مستوى لواجهة برمجة تطبيقات Car App API متوافق مع تطبيق مضيف، استخدِم الطريقة
getCarAppApiLevel()
.
عليك الإفصاح عن الحد الأدنى لمستوى Car App API الذي يتيحه تطبيقك في ملف AndroidManifest.xml
:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
راجِع مستندات
التعليق التوضيحي RequiresCarApi
للحصول على تفاصيل حول كيفية الحفاظ على التوافق مع الإصدارات القديمة وتحديد
الحد الأدنى لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام إحدى الميزات. للاطّلاع على تعريف لمستوى واجهة برمجة التطبيقات المطلوب لاستخدام ميزة معيّنة في "مكتبة تطبيقات السيارات"، راجِع مستندات المرجع الخاصة CarAppApiLevels
.
إنشاء CarAppService وSession
يجب أن يوسّع تطبيقك الفئة
CarAppService
وأن ينفّذ
طريقتها
onCreateSession
التي تعرض مثيلاً من Session
يتوافق مع الاتصال الحالي بالمضيف:
Kotlin
class HelloWorldService : CarAppService() { ... override fun onCreateSession(): Session { return HelloWorldSession() } ... }
Java
public final class HelloWorldService extends CarAppService { ... @Override @NonNull public Session onCreateSession() { return new HelloWorldSession(); } ... }
يكون عنصر Session
مسؤولاً عن عرض عنصر Screen
عند بدء تشغيل التطبيق للمرة الأولى:
Kotlin
class HelloWorldSession : Session() { ... override fun onCreateScreen(intent: Intent): Screen { return HelloWorldScreen(carContext) } ... }
Java
public final class HelloWorldSession extends Session { ... @Override @NonNull public Screen onCreateScreen(@NonNull Intent intent) { return new HelloWorldScreen(getCarContext()); } ... }
للتعامل مع السيناريوهات التي يحتاج فيها تطبيق السيارة إلى البدء من شاشة ليست الشاشة الرئيسية أو صفحة الوصول في تطبيقك، مثل التعامل مع الروابط لصفحات في التطبيق، يمكنك إعداد مسبق لمجموعة من الشاشات السابقة باستخدام
ScreenManager.push
قبل الرجوع من
onCreateScreen
.
تتيح عملية التعبئة المسبقة للمستخدمين الرجوع إلى الشاشات السابقة من الشاشة الأولى التي يعرضها تطبيقك.
إنشاء شاشة البدء
يمكنك إنشاء الشاشات التي يعرضها تطبيقك من خلال تحديد الفئات التي توسّع الفئة
Screen
وتنفيذ الطريقة
onGetTemplate
الخاصة بها، والتي تعرض مثيلاً من
Template
يمثّل حالة واجهة المستخدم التي سيتم عرضها على شاشة السيارة.
يوضّح المقتطف التالي كيفية تعريف Screen
يستخدم نموذج PaneTemplate
لعرض السلسلة البسيطة "Hello world!":
Kotlin
class HelloWorldScreen(carContext: CarContext) : Screen(carContext) { override fun onGetTemplate(): Template { val row = Row.Builder().setTitle("Hello world!").build() val pane = Pane.Builder().addRow(row).build() return PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build() } }
Java
public class HelloWorldScreen extends Screen { @NonNull @Override public Template onGetTemplate() { Row row = new Row.Builder().setTitle("Hello world!").build(); Pane pane = new Pane.Builder().addRow(row).build(); return new PaneTemplate.Builder(pane) .setHeaderAction(Action.APP_ICON) .build(); } }
فئة CarContext
الفئة CarContext
هي فئة فرعية ContextWrapper
يمكن الوصول إليها من خلال مثيلات Session
وScreen
. توفّر هذه المكتبة إمكانية الوصول إلى خدمات السيارة، مثل ScreenManager
لإدارة حزمة الشاشة وAppManager
للوظائف العامة المتعلقة بالتطبيقات، مثل الوصول إلى العنصر Surface
من أجل رسم الخرائط وNavigationManager
الذي تستخدمه تطبيقات التنقّل خطوة بخطوة لإرسال بيانات التنقّل الوصفية وغيرها من الأحداث المتعلقة بالتنقّل إلى التطبيق المضيف.
يمكنك الاطّلاع على الوصول إلى نماذج التنقّل للحصول على قائمة شاملة بوظائف المكتبة المتاحة لتطبيقات التنقّل.
توفّر CarContext
أيضًا وظائف أخرى، مثل السماح لك بتحميل موارد قابلة للرسم باستخدام الإعدادات من شاشة السيارة، وبدء تطبيق في السيارة باستخدام الأهداف، وتحديد ما إذا كان يجب أن يعرض تطبيقك الخريطة في المظهر الداكن.
تنفيذ التنقّل بين الشاشات
تعرض التطبيقات غالبًا عددًا من الشاشات المختلفة، وقد تستخدم كل شاشة قوالب مختلفة يمكن للمستخدم التنقّل بينها أثناء تفاعله مع الواجهة المعروضة على الشاشة.
تقدّم الفئة ScreenManager
حزمة شاشات يمكنك استخدامها لعرض الشاشات التي يمكن إغلاقها تلقائيًا عندما ينقر المستخدم على زر الرجوع في شاشة السيارة أو يستخدم زر الرجوع المتاح في بعض السيارات.
يوضّح المقتطف التالي كيفية إضافة إجراء رجوع إلى نموذج رسالة، بالإضافة إلى إجراء يعرض شاشة جديدة عند اختيارها من قِبل المستخدم:
Kotlin
val template = MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( Action.Builder() .setTitle("Next screen") .setOnClickListener { screenManager.push(NextScreen(carContext)) } .build()) .build()
Java
MessageTemplate template = new MessageTemplate.Builder("Hello world!") .setHeaderAction(Action.BACK) .addAction( new Action.Builder() .setTitle("Next screen") .setOnClickListener( () -> getScreenManager().push(new NextScreen(getCarContext()))) .build()) .build();
العنصر Action.BACK
هو Action
عادي يستدعي ScreenManager.pop
تلقائيًا.
يمكن تجاهل هذا السلوك باستخدام مثيل
OnBackPressedDispatcher
المتاح من
CarContext
.
للمساعدة في ضمان أمان استخدام التطبيق أثناء القيادة، يمكن أن يبلغ الحد الأقصى لعمق حزمة الشاشة خمس شاشات. يمكنك الاطّلاع على قسم القيود المفروضة على النماذج للحصول على مزيد من التفاصيل.
إعادة تحميل محتوى نموذج
يمكن لتطبيقك طلب إبطال محتوى
Screen
من خلال استدعاء الطريقة
Screen.invalidate
.
يُجري المضيف بعد ذلك عملية استدعاء إلى طريقة
Screen.onGetTemplate
في تطبيقك لاسترداد النموذج مع المحتوى الجديد.
عند إعادة تحميل Screen
، من المهم معرفة المحتوى المحدّد في النموذج الذي يمكن تعديله حتى لا يحتسب المضيف النموذج الجديد ضمن حصة النماذج.
يمكنك الاطّلاع على قسم قيود النماذج لمزيد من التفاصيل.
لقد نصحناك بتنظيم شاشاتك بحيث يكون هناك تطابق واحد إلى واحد بين Screen
ونوع النموذج الذي يعرضه من خلال عملية تنفيذ onGetTemplate
.
رسم الخرائط
يمكن لتطبيقات التنقّل ونقاط الاهتمام والطقس التي تستخدم النماذج التالية رسم الخرائط من خلال الوصول إلى Surface
.
لاستخدام النماذج التالية، يجب أن يتضمّن تطبيقك أحد الأذونات ذات الصلة في العنصر <uses-permission>
ضمن ملف AndroidManifest.xml
.
نموذج | إذن النموذج | إرشادات الفئة |
---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
التنقل |
MapWithContentTemplate |
androidx.car.app.NAVIGATION_TEMPLATES أو androidx.car.app.MAP_TEMPLATES |
التنقّل، نقاط الاهتمام، الطقس |
MapTemplate (تم إيقافها نهائيًا) |
androidx.car.app.NAVIGATION_TEMPLATES |
التنقل |
PlaceListNavigationTemplate (تم إيقافها نهائيًا) |
androidx.car.app.NAVIGATION_TEMPLATES |
التنقل |
RoutePreviewNavigationTemplate (تم إيقافها نهائيًا) |
androidx.car.app.NAVIGATION_TEMPLATES |
التنقل |
تضمين إذن العرض على السطح
بالإضافة إلى الإذن المطلوب للنموذج الذي يستخدمه تطبيقك، يجب أن يدرج تطبيقك الإذن androidx.car.app.ACCESS_SURFACE
في ملف AndroidManifest.xml
الخاص به للوصول إلى مساحة العرض:
<manifest ...>
...
<uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
...
</manifest>
الوصول إلى مساحة العرض
للوصول إلى Surface
الذي يوفّره المضيف، عليك تنفيذ SurfaceCallback
وتقديم هذا التنفيذ إلى خدمة السيارة AppManager
. يتم تمرير Surface
الحالي إلى SurfaceCallback
في المَعلمة SurfaceContainer
ضمن عمليات الاسترجاع onSurfaceAvailable()
وonSurfaceDestroyed()
.
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
فهم مساحة العرض المرئية على السطح
يمكن للمضيف رسم عناصر واجهة المستخدم للنماذج فوق الخريطة. يُبلغ المضيف عن مساحة السطح التي يُضمن عدم حجبها وأنّها مرئية بالكامل للمستخدم من خلال استدعاء الطريقة SurfaceCallback.onVisibleAreaChanged
. بالإضافة إلى ذلك، للحدّ من عدد التغييرات، يستدعي المضيف طريقة
SurfaceCallback.onStableAreaChanged
باستخدام أصغر مستطيل، والذي يظهر دائمًا استنادًا إلى النموذج الحالي.
على سبيل المثال، عندما يستخدم تطبيق خرائط
NavigationTemplate
مع شريط إجراءات في الأعلى، يمكن لشريط الإجراءات أن يخفي نفسه عندما لا يتفاعل المستخدم مع الشاشة لفترة من الوقت لتوفير مساحة أكبر للخريطة. في هذه الحالة، هناك دالة ردّ الاتصال إلى onStableAreaChanged
وonVisibleAreaChanged
مع المستطيل نفسه. عند إخفاء شريط الإجراءات،
يتم استدعاء onVisibleAreaChanged
فقط مع المساحة الأكبر. إذا تفاعل المستخدم مع الشاشة، سيتم استدعاء onVisibleAreaChanged
مرة أخرى فقط مع المستطيل الأول.
توفير المظهر الداكن
يجب أن تعيد التطبيقات رسم الخريطة على مثيل Surface
باستخدام ألوان داكنة مناسبة عندما يحدّد المضيف أنّ الظروف تستدعي ذلك، كما هو موضّح في جودة تطبيقات Android للسيارات.
لتحديد ما إذا كان سيتم رسم خريطة داكنة، يمكنك استخدام طريقة
CarContext.isDarkMode
. عندما تتغيّر حالة المظهر الداكن، ستتلقّى طلبًا إلى
Session.onCarConfigurationChanged
.
رسم الخرائط على شاشة العرض
بالإضافة إلى رسم الخرائط على الشاشة الرئيسية، يمكن لتطبيقات التنقّل أيضًا رسم الخرائط على شاشة مجموعة العدادات خلف عجلة القيادة. اطّلِع على الرسم على شاشة العرض المجمّعة للحصول على إرشادات إضافية.
السماح للمستخدمين بالتفاعل مع الخريطة
عند استخدام النماذج التالية، يمكنك إتاحة تفاعل المستخدمين مع الخرائط التي ترسمها، مثل السماح لهم بالاطّلاع على أجزاء مختلفة من الخريطة من خلال التكبير والتصغير والتحريك.
نموذج | التفاعل متاح منذ مستوى Car App API |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (متوقّف نهائيًا) |
4 |
RoutePreviewNavigationTemplate (متوقّف نهائيًا) |
4 |
MapTemplate (متوقّف نهائيًا) |
5 (مقدمة عن النموذج) |
MapWithContentTemplate |
7 (مقدمة عن النموذج) |
تنفيذ عمليات معاودة الاتصال المتعلقة بالتفاعل
تحتوي واجهة SurfaceCallback
على العديد من طرق معاودة الاتصال التي يمكنك تنفيذها لإضافة تفاعلية إلى الخرائط التي تم إنشاؤها
باستخدام النماذج في القسم السابق:
التفاعل | طريقة واحدة (SurfaceCallback ) |
متوافق منذ مستوى Car App API |
---|---|---|
نقر | onClick |
5 |
استخدام إصبعين للتصغير | onScale |
2 |
السحب بلمسة واحدة | onScroll |
2 |
نقل المحتوى بلمسة واحدة | onFling |
2 |
النقر مرتين | onScale (مع تحديد عامل التحجيم من خلال المضيف النموذجي) |
2 |
الدفع الدائري في وضع العرض الشامل | onScroll (مع عامل المسافة الذي يحدّده المضيف الرئيسي) |
2 |
إضافة شريط إجراءات خريطة
يمكن أن تتضمّن هذه النماذج شريط إجراءات الخريطة لتنفيذ إجراءات متعلقة بالخريطة، مثل التكبير والتصغير وإعادة التوسيط وعرض البوصلة وغيرها من الإجراءات التي تختار عرضها. يمكن أن يحتوي شريط إجراءات الخريطة على ما يصل إلى أربعة أزرار تتضمّن رموزًا فقط يمكن إعادة تحميلها بدون التأثير في عمق المهمة. يتم إخفاء شريط التنقل في وضع الخمول ويظهر مجددًا في وضع النشاط.
لتلقّي عمليات ردّ الاتصال التفاعلية الخاصة بالخريطة،
يجب إضافة زر Action.PAN
في شريط إجراءات الخريطة. عندما يضغط المستخدم على زر التحريك، يدخل الجهاز المضيف في وضع التحريك، كما هو موضّح في القسم التالي.
إذا حذف تطبيقك الزر Action.PAN
في شريط إجراءات الخريطة، لن يتلقّى إدخالات المستخدم من الطريقتين SurfaceCallback
، وسيخرج المضيف من أي وضع تحريك تم تفعيله سابقًا.
على شاشة تعمل باللمس، لا يظهر زر التحريك.
التعرّف على وضع العرض الشامل
في وضع التحريك، يحوّل مضيف النموذج إدخال المستخدم من أجهزة الإدخال غير اللمسية، مثل وحدات التحكّم الدورانية ولوحات اللمس، إلى طرق SurfaceCallback
المناسبة. استجِب لإجراء المستخدم للدخول إلى وضع العرض الشامل أو الخروج منه باستخدام الطريقة setPanModeListener
في NavigationTemplate.Builder
. يمكن للمضيف إخفاء عناصر أخرى من واجهة المستخدم في النموذج أثناء استخدام وضع التحريك.
التفاعل مع المستخدم
يمكن لتطبيقك التفاعل مع المستخدم باستخدام أنماط مشابهة لتطبيق الأجهزة الجوّالة.
التعامل مع بيانات المستخدم
يمكن لتطبيقك الاستجابة لإدخالات المستخدمين من خلال تمرير أدوات المعالجة المناسبة إلى النماذج التي تتوافق معها. يوضّح المقتطف التالي كيفية إنشاء نموذج
Action
يضبط
OnClickListener
الذي
يُعيد الاتصال بطريقة محدّدة في رمز تطبيقك:
Kotlin
val action = Action.Builder() .setTitle("Navigate") .setOnClickListener(::onClickNavigate) .build()
Java
Action action = new Action.Builder() .setTitle("Navigate") .setOnClickListener(this::onClickNavigate) .build();
يمكن أن تبدأ الطريقة onClickNavigate
بعد ذلك
تطبيق التنقّل التلقائي للسيارة
باستخدام الطريقة
CarContext.startCarApp
:
Kotlin
private fun onClickNavigate() { val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)) carContext.startCarApp(intent) }
Java
private void onClickNavigate() { Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address)); getCarContext().startCarApp(intent); }
لمزيد من التفاصيل حول كيفية بدء تشغيل التطبيقات، بما في ذلك تنسيق الغرض ACTION_NAVIGATE
، راجِع القسم بدء تشغيل تطبيق على السيارة باستخدام غرض.
لا يُسمح بتنفيذ بعض الإجراءات، مثل تلك التي تتطلّب توجيه المستخدم لمواصلة التفاعل على أجهزته الجوّالة، إلا عندما تكون السيارة متوقفة.
يمكنك استخدام
ParkedOnlyOnClickListener
لتنفيذ هذه الإجراءات. إذا لم تكن السيارة متوقفة، يعرض الجهاز المضيف إشارة للمستخدم بأنّه لا يُسمح بتنفيذ الإجراء في هذه الحالة. إذا كانت السيارة متوقفة، سيتم تنفيذ الرمز البرمجي بشكل طبيعي. تعرض المقتطفة التالية كيفية استخدام ParkedOnlyOnClickListener
لفتح شاشة الإعدادات على الجهاز الجوّال:
Kotlin
val row = Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone)) .build()
Java
Row row = new Row.Builder() .setTitle("Open Settings") .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone)) .build();
عرض الإشعارات
لا تظهر الإشعارات المُرسَلة إلى الجهاز الجوّال على شاشة السيارة إلا إذا تم توسيعها باستخدام CarAppExtender
.
يمكن ضبط بعض سمات الإشعارات، مثل عنوان المحتوى والنص والرمز والإجراءات، في CarAppExtender
، ما يؤدي إلى تجاهل سمات الإشعارات عند ظهورها على شاشة السيارة.
يوضّح المقتطف التالي كيفية إرسال إشعار إلى شاشة السيارة يعرض عنوانًا مختلفًا عن العنوان المعروض على الجهاز الجوّال:
Kotlin
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build()
Java
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) .setContentTitle(titleOnThePhone) .extend( new CarAppExtender.Builder() .setContentTitle(titleOnTheCar) ... .build()) .build();
يمكن أن تؤثر الإشعارات في الأجزاء التالية من واجهة المستخدم:
- قد يتم عرض إشعار تنبيه للمستخدم.
- يمكن إضافة إدخال في مركز الإشعارات، مع شارة مرئية في الشريط بشكل اختياري.
- بالنسبة إلى تطبيقات الملاحة، قد يظهر الإشعار في أداة شريط التنقّل كما هو موضّح في الإشعارات خطوة بخطوة.
يمكنك اختيار طريقة ضبط إشعارات تطبيقك للتأثير في كل عنصر من عناصر واجهة المستخدم هذه باستخدام أولوية الإشعار، كما هو موضّح في مستندات CarAppExtender
.
إذا تم استدعاء
NotificationCompat.Builder.setOnlyAlertOnce
بالقيمة true
، سيتم عرض إشعار ذي أولوية عالية كإشعار HUN مرة واحدة فقط.
لمزيد من المعلومات حول كيفية تصميم إشعارات تطبيق السيارة، راجِع دليل Google Design for Driving حول الإشعارات.
عرض الإشعارات المنبثقة
يمكن لتطبيقك عرض إشعار مؤقت باستخدام
CarToast
كما هو موضّح في المقتطف التالي:
Kotlin
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
Java
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
طلب الأذونات
إذا كان تطبيقك يحتاج إلى الوصول إلى بيانات أو إجراءات محظورة، مثل الموقع الجغرافي، تسري القواعد العادية لأذونات Android. لطلب الحصول على إذن، يمكنك استخدام طريقة
CarContext.requestPermissions()
.
تتمثّل فائدة استخدام CarContext.requestPermissions()
بدلاً من واجهات برمجة التطبيقات العادية في Android في أنّك لست بحاجة إلى تشغيل Activity
لإنشاء مربّع حوار الأذونات. بالإضافة إلى ذلك، يمكنك استخدام الرمز البرمجي نفسه على كل من Android Auto وAndroid Automotive OS، بدلاً من الاضطرار إلى إنشاء مسارات تعتمد على النظام الأساسي.
تنسيق مربّع حوار الأذونات على Android Auto
في Android Auto، سيظهر مربّع حوار الأذونات للمستخدم على الهاتف.
لن تظهر أي خلفية تلقائيًا خلف مربع الحوار. لضبط خلفية مخصّصة، عليك تعريف مظهر تطبيق السيارة في ملف AndroidManifest.xml
وضبط السمة carPermissionActivityLayout
لمظهر تطبيق السيارة.
<meta-data android:name="androidx.car.app.theme" android:resource="@style/MyCarAppTheme />
بعد ذلك، اضبط السمة carPermissionActivityLayout
لمظهر تطبيق السيارة:
<resources> <style name="MyCarAppTheme"> <item name="carPermissionActivityLayout">@layout/my_custom_background</item> </style> </resources>
بدء تطبيق سيارة باستخدام هدف
يمكنك استدعاء الطريقة
CarContext.startCarApp
لتنفيذ أحد الإجراءات التالية:
- افتح تطبيق "برنامج الاتصال" لإجراء مكالمة هاتفية.
- ابدأ التنقّل بشكل مفصّل إلى موقع جغرافي باستخدام تطبيق التنقّل التلقائي بالسيارة.
- ابدأ تطبيقك الخاص باستخدام هدف.
يوضّح المثال التالي كيفية إنشاء إشعار يتضمّن إجراءً يفتح تطبيقك مع شاشة تعرض تفاصيل حجز مكان لصف السيارة.
يمكنك توسيع مثيل الإشعار باستخدام رسالة Intent تتضمّن محتوى يحتوي على
PendingIntent
يغلّف رسالة Intent صريحة
لإجراء تطبيقك:
Kotlin
val notification = notificationBuilder ... .extend( CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(ComponentName(context, MyNotificationReceiver::class.java)), 0)) .build())
Java
Notification notification = notificationBuilder ... .extend( new CarAppExtender.Builder() .setContentIntent( PendingIntent.getBroadcast( context, ACTION_VIEW_PARKING_RESERVATION.hashCode(), new Intent(ACTION_VIEW_PARKING_RESERVATION) .setComponent(new ComponentName(context, MyNotificationReceiver.class)), 0)) .build());
يجب أن يوضّح تطبيقك أيضًا
BroadcastReceiver
يتم استدعاؤه
لمعالجة الغرض عندما يختار المستخدم الإجراء في
واجهة الإشعارات ويستدعي
CarContext.startCarApp
مع غرض يتضمّن معرّف الموارد المنتظم للبيانات:
Kotlin
class MyNotificationReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { val intentAction = intent.action if (ACTION_VIEW_PARKING_RESERVATION == intentAction) { CarContext.startCarApp( intent, Intent(Intent.ACTION_VIEW) .setComponent(ComponentName(context, MyCarAppService::class.java)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))) } } }
Java
public class MyNotificationReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { String intentAction = intent.getAction(); if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) { CarContext.startCarApp( intent, new Intent(Intent.ACTION_VIEW) .setComponent(new ComponentName(context, MyCarAppService.class)) .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction))); } } }
أخيرًا، تعالج طريقة
Session.onNewIntent
في تطبيقك هذا الغرض عن طريق عرض شاشة حجز مكان انتظار السيارات
في الحزمة، إذا لم تكن معروضة في المقدّمة:
Kotlin
override fun onNewIntent(intent: Intent) { val screenManager = carContext.getCarService(ScreenManager::class.java) val uri = intent.data if (uri != null && MY_URI_SCHEME == uri.scheme && MY_URI_HOST == uri.schemeSpecificPart && ACTION_VIEW_PARKING_RESERVATION == uri.fragment ) { val top = screenManager.top if (top !is ParkingReservationScreen) { screenManager.push(ParkingReservationScreen(carContext)) } } }
Java
@Override public void onNewIntent(@NonNull Intent intent) { ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class); Uri uri = intent.getData(); if (uri != null && MY_URI_SCHEME.equals(uri.getScheme()) && MY_URI_HOST.equals(uri.getSchemeSpecificPart()) && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment()) ) { Screen top = screenManager.getTop(); if (!(top instanceof ParkingReservationScreen)) { screenManager.push(new ParkingReservationScreen(getCarContext())); } } }
راجِع قسم عرض الإشعارات للحصول على مزيد من المعلومات حول كيفية التعامل مع الإشعارات في تطبيق السيارة.
قيود النماذج
يحدّد المضيف عدد النماذج التي سيتم عرضها لمهمة معيّنة بما لا يزيد عن خمسة نماذج، ويجب أن يكون النموذج الأخير أحد الأنواع التالية:
NavigationTemplate
PaneTemplate
MessageTemplate
MediaPlaybackTemplate
SignInTemplate
LongMessageTemplate
يُرجى العلم أنّ هذا الحدّ ينطبق على عدد النماذج وليس على عدد مثيلات Screen
في الحزمة. على سبيل المثال، إذا أرسل تطبيق نموذجين أثناء عرض الشاشة (أ) ثم عرض الشاشة (ب)، يمكنه الآن إرسال ثلاثة نماذج أخرى. بدلاً من ذلك، إذا كانت كل شاشة منظَّمة لإرسال نموذج واحد، يمكن للتطبيق إرسال خمسة مثيلات شاشة إلى حزمة ScreenManager
.
هناك حالات خاصة لهذه القيود، وهي عمليات إعادة تحميل النموذج والرجوع وإعادة الضبط.
إعادة تحميل النماذج
لا يتم احتساب بعض تحديثات المحتوى ضمن الحدّ الأقصى للنماذج. بشكل عام، إذا أرسل تطبيق نموذجًا جديدًا من النوع نفسه ويتضمّن المحتوى الرئيسي نفسه الذي يتضمّنه النموذج السابق، لن يتم احتساب النموذج الجديد ضمن الحصة المحدّدة. على سبيل المثال، لا يتم احتساب تعديل حالة زر التبديل لصف في ListTemplate
ضمن الحصة المحدّدة. يمكنك الاطّلاع على مستندات النماذج الفردية لمعرفة المزيد من المعلومات حول أنواع تعديلات المحتوى التي يمكن اعتبارها إعادة تحميل.
عمليات الخلفية
لتفعيل التدفقات الفرعية ضمن مهمة، يرصد المضيف متى يعرض التطبيق Screen
من حزمة ScreenManager
ويعدّل الحصة المتبقية استنادًا إلى عدد النماذج التي يتراجع التطبيق عنها.
على سبيل المثال، إذا أرسل التطبيق نموذجين أثناء عرض الشاشة (أ)، ثم عرض الشاشة (ب) وأرسل نموذجين آخرين، سيتبقى للتطبيق حصة واحدة. إذا عاد التطبيق بعد ذلك إلى الشاشة (أ)، يعيد المضيف ضبط الحصة إلى ثلاث، لأنّ التطبيق قد عاد خطوتين إلى الوراء.
يُرجى العِلم أنّه عند الرجوع إلى شاشة سابقة، يجب أن يرسل التطبيق نموذجًا من النوع نفسه الذي أرسلته الشاشة آخر مرة. سيؤدي إرسال أي نوع آخر من النماذج إلى حدوث خطأ. ومع ذلك، طالما ظل النوع كما هو أثناء عملية الرجوع، يمكن للتطبيق تعديل محتوى النموذج بحرية بدون التأثير في الحصة.
عمليات إعادة الضبط
تتضمّن بعض النماذج دلالات خاصة تشير إلى نهاية مهمة. على سبيل المثال،
NavigationTemplate
هي طريقة عرض من المتوقّع أن تبقى على الشاشة ويتم تحديثها بتعليمات جديدة
للمستخدم. عندما يصل إلى أحد هذه النماذج، يعيد المضيف ضبط حصة النموذج، ويتعامل مع هذا النموذج كما لو كان الخطوة الأولى في مهمة جديدة. يسمح هذا للتطبيق ببدء مهمة جديدة.
راجِع مستندات النماذج الفردية لمعرفة النماذج التي تؤدي إلى إعادة الضبط على الجهاز المضيف.
إذا تلقّى المضيف إشارة لبدء التطبيق من إجراء إشعار أو من مشغّل التطبيق، تتم إعادة ضبط الحصة أيضًا. تتيح هذه الآلية للتطبيق بدء مسار مهام جديد من الإشعارات، ويسري ذلك حتى إذا كان التطبيق مرتبطًا ومفتوحًا في المقدّمة.
راجِع قسم عرض الإشعارات لمزيد من التفاصيل حول كيفية عرض إشعارات تطبيقك على شاشة السيارة. راجِع قسم بدء تطبيق سيارة باستخدام intent للحصول على معلومات حول كيفية بدء تطبيقك من خلال إجراء إشعار.
واجهة برمجة التطبيقات Connection API
يمكنك تحديد ما إذا كان تطبيقك يعمل على Android Auto أو Android Automotive OS باستخدام واجهة برمجة التطبيقات CarConnection
لاسترداد معلومات الاتصال في وقت التشغيل.
على سبيل المثال، في Session
ضمن تطبيق السيارة، يمكنك ضبط قيمة أولية لـ CarConnection
والاشتراك في تلقّي تحديثات LiveData
:
Kotlin
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
Java
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);
في أداة المراقبة، يمكنك بعد ذلك التفاعل مع التغييرات في حالة الاتصال:
Kotlin
fun onConnectionStateUpdated(connectionState: Int) { val message = when(connectionState) { CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit" CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS" CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto" else -> "Unknown car connection type" } CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show() }
Java
private void onConnectionStateUpdated(int connectionState) { String message; switch(connectionState) { case CarConnection.CONNECTION_TYPE_NOT_CONNECTED: message = "Not connected to a head unit"; break; case CarConnection.CONNECTION_TYPE_NATIVE: message = "Connected to Android Automotive OS"; break; case CarConnection.CONNECTION_TYPE_PROJECTION: message = "Connected to Android Auto"; break; default: message = "Unknown car connection type"; break; } CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show(); }
Constraints API
قد تسمح السيارات المختلفة بعرض عدد مختلف من مثيلات Item
للمستخدم في المرة الواحدة. استخدِم
ConstraintManager
للتحقّق من حد المحتوى في وقت التشغيل وضبط عدد العناصر المناسب
في النماذج.
ابدأ بالحصول على ConstraintManager
من CarContext
:
Kotlin
val manager = carContext.getCarService(ConstraintManager::class.java)
Java
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);
يمكنك بعد ذلك طلب البحث عن عنصر ConstraintManager
الذي تم استرجاعه للحصول على الحدّ الأقصى المسموح به للمحتوى ذي الصلة. على سبيل المثال، للحصول على عدد العناصر التي يمكن عرضها في شبكة، استخدِم الدالة
getContentLimit
مع
CONTENT_LIMIT_TYPE_GRID
:
Kotlin
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
Java
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
إضافة مسار تسجيل دخول
إذا كان تطبيقك يوفّر للمستخدمين تجربة تسجيل الدخول، يمكنك استخدام نماذج مثل SignInTemplate
وLongMessageTemplate
مع مستوى 2 من Car App API أو أعلى للتعامل مع تسجيل الدخول إلى تطبيقك على وحدة رأس السيارة.
لإنشاء SignInTemplate
، حدِّد SignInMethod
. تتيح "مكتبة تطبيقات السيارات" حاليًا طرق تسجيل الدخول التالية:
InputSignInMethod
لتسجيل الدخول باستخدام اسم المستخدم وكلمة المرورPinSignInMethod
لتسجيل الدخول باستخدام رقم التعريف الشخصي، حيث يربط المستخدم حسابه من هاتفه باستخدام رقم التعريف الشخصي المعروض على وحدة السيارة الرئيسية.ProviderSignInMethod
لتسجيل الدخول باستخدام موفِّر خدمة، مثل تسجيل الدخول باستخدام حساب Google وOne Tap.QRCodeSignInMethod
لتسجيل الدخول باستخدام رمز الاستجابة السريعة، حيث يمسح المستخدم رمز الاستجابة السريعة ضوئيًا لإكمال عملية تسجيل الدخول على هاتفه. تتوفّر هذه الميزة مع الإصدار 4 من Car API والإصدارات الأحدث.
على سبيل المثال، لتنفيذ نموذج يجمع كلمة مرور المستخدم، ابدأ بإنشاء InputCallback
لمعالجة مدخلات المستخدم والتحقّق من صحتها:
Kotlin
val callback = object : InputCallback { override fun onInputSubmitted(text: String) { // You will receive this callback when the user presses Enter on the keyboard. } override fun onInputTextChanged(text: String) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } }
Java
InputCallback callback = new InputCallback() { @Override public void onInputSubmitted(@NonNull String text) { // You will receive this callback when the user presses Enter on the keyboard. } @Override public void onInputTextChanged(@NonNull String text) { // You will receive this callback as the user is typing. The update // frequency is determined by the host. } };
يجب إدخال InputCallback
لـ InputSignInMethod
Builder
.
Kotlin
val passwordInput = InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build()
Java
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback) .setHint("Password") .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD) ... .build();
أخيرًا، استخدِم InputSignInMethod
الجديد لإنشاء SignInTemplate
.
Kotlin
SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build()
Java
new SignInTemplate.Builder(passwordInput) .setTitle("Sign in with username and password") .setInstructions("Enter your password") .setHeaderAction(Action.BACK) ... .build();
استخدام AccountManager
يجب أن تستخدم التطبيقات التي تعمل بنظام التشغيل Android Automotive والتي تتطلّب مصادقة AccountManager للأسباب التالية:
- تجربة مستخدم أفضل وسهولة إدارة الحسابات: يمكن للمستخدمين إدارة جميع حساباتهم بسهولة من قائمة الحسابات في إعدادات النظام، بما في ذلك تسجيل الدخول وتسجيل الخروج.
- تجارب "الضيف": بما أنّ السيارات هي أجهزة مشترَكة، يمكن للمصنّعين الأصليين للأجهزة تفعيل تجارب "الضيف" في السيارة، حيث لا يمكن إضافة حسابات.
إضافة صيغ مختلفة لسلسلة النص
قد تعرض أحجام شاشات السيارات المختلفة كميات مختلفة من النص. باستخدام Car App API
المستوى 2 والإصدارات الأحدث، يمكنك تحديد عدة صيغ لسلسلة نصية لتناسب الشاشة على أفضل وجه. لمعرفة الأماكن التي يتم فيها قبول صيغ النص، ابحث عن النماذج والمكوّنات التي تتضمّن CarText
.
يمكنك إضافة صيغ مختلفة لسلسلة نصية إلى CarText
باستخدام طريقة CarText.Builder.addVariant()
:
Kotlin
val itemTitle = CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build()
Java
CarText itemTitle = new CarText.Builder("This is a very long string") .addVariant("Shorter string") ... .build();
يمكنك بعد ذلك استخدام هذا CarText
، مثلاً كنص أساسي في GridItem
.
Kotlin
GridItem.Builder() .addTitle(itemTitle) ... .build()
Java
new GridItem.Builder() .addTitle(itemTitle) ... build();
أضِف السلاسل بالترتيب من الأكثر تفضيلاً إلى الأقل تفضيلاً، مثلاً من الأطول إلى الأقصر. يختار المضيف السلسلة المناسبة للطول استنادًا إلى مقدار المساحة المتوفّرة على شاشة السيارة.
إضافة CarIcons مضمّنة للصفوف
يمكنك إضافة رموز مضمّنة مع النص لتحسين المظهر المرئي لتطبيقك باستخدام
CarIconSpan
.
راجِع مستندات
CarIconSpan.create
للحصول على مزيد من المعلومات حول إنشاء هذه النطاقات. يمكنك الاطّلاع على
تنسيق نص Spantastic باستخدام النطاقات للحصول على نظرة عامة حول طريقة عمل تنسيق النص باستخدام النطاقات.
Kotlin
val rating = SpannableString("Rating: 4.5 stars") rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ) val row = Row.Builder() ... .addText(rating) .build()
Java
SpannableString rating = new SpannableString("Rating: 4.5 stars"); rating.setSpan( CarIconSpan.create( // Create a CarIcon with an image of four and a half stars new CarIcon.Builder(...).build(), // Align the CarIcon to the baseline of the text CarIconSpan.ALIGN_BASELINE ), // The start index of the span (index of the character '4') 8, // The end index of the span (index of the last 's' in "stars") 16, Spanned.SPAN_INCLUSIVE_INCLUSIVE ); Row row = new Row.Builder() ... .addText(rating) .build();
Car Hardware APIs
بدءًا من المستوى 3 من Car App API، تتضمّن Car App Library واجهات برمجة تطبيقات يمكنك استخدامها للوصول إلى خصائص المركبة وأجهزة الاستشعار.
المتطلبات
لاستخدام واجهات برمجة التطبيقات مع Android Auto، ابدأ بإضافة تبعية إلى
androidx.car.app:app-projected
في ملف build.gradle
لوحدة Android Auto. بالنسبة إلى نظام التشغيل Android Automotive، أضِف تبعية إلى
androidx.car.app:app-automotive
في ملف build.gradle
لوحدة Android Automotive OS.
بالإضافة إلى ذلك، عليك في ملف AndroidManifest.xml
تضمين بيان بالأذونات ذات الصلة المطلوبة
لطلب بيانات السيارة التي تريد استخدامها. يُرجى العِلم أنّه يجب أن يمنحك المستخدم هذه الأذونات أيضًا. يمكنك استخدام الرمز البرمجي نفسه على كل من Android Auto وAndroid Automotive OS، بدلاً من الاضطرار إلى إنشاء مسارات تعتمد على النظام الأساسي. ومع ذلك، تختلف الأذونات المطلوبة.
CarInfo
يوضّح هذا الجدول الخصائص التي تعرضها واجهات برمجة التطبيقات CarInfo
والأذونات التي عليك طلبها لاستخدامها:
الطرق | الخصائص | أذونات Android Auto | أذونات نظام التشغيل Android Automotive | متوافق منذ مستوى Car App API |
---|---|---|---|---|
fetchModel |
الصنع والطراز والسنة | android.car.permission.CAR_INFO |
3 | |
fetchEnergyProfile |
أنواع وصلات المركبات الكهربائية وأنواع الوقود | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_INFO |
3 |
fetchExteriorDimensions
لا تتوفّر هذه البيانات إلا على بعض المركبات التي تعمل بنظام التشغيل Android Automotive والتي تستخدم الإصدار 30 أو الإصدارات الأحدث من واجهة برمجة التطبيقات |
الأبعاد الخارجية | لا ينطبق | android.car.permission.CAR_INFO |
7 |
addTollListener
removeTollListener |
حالة بطاقة تحصيل رسوم العبور ونوعها | 3 | ||
addEnergyLevelListener
removeEnergyLevelListener |
مستوى شحن البطارية ومستوى الوقود ومستوى الوقود منخفض والمدى المتبقي | com.google.android.gms.permission.CAR_FUEL |
android.car.permission.CAR_ENERGY ،android.car.permission.CAR_ENERGY_PORTS ،android.car.permission.READ_CAR_DISPLAY_UNITS
|
3 |
addSpeedListener
removeSpeedListener |
السرعة الأولية، وسرعة العرض (المعروضة على شاشة مجموعة العدادات في السيارة) | com.google.android.gms.permission.CAR_SPEED |
android.car.permission.CAR_SPEED ،android.car.permission.READ_CAR_DISPLAY_UNITS |
3 |
addMileageListener
removeMileageListener
تحذير: اسم طريقة |
مسافة عدّاد المسافات | com.google.android.gms.permission.CAR_MILEAGE |
لا تتوفّر هذه البيانات على نظام التشغيل Android Automotive للتطبيقات المثبَّتة من "متجر Play". | 3 |
على سبيل المثال، للحصول على النطاق المتبقي، أنشئ مثيلاً من الكائن CarInfo
، ثم أنشئ OnCarDataAvailableListener
وسجِّله:
Kotlin
val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo val listener = OnCarDataAvailableListener<EnergyLevel> { data -> if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) { val rangeRemaining = data.rangeRemainingMeters.value } else { // Handle error } } carInfo.addEnergyLevelListener(carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener)
Java
CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo(); OnCarDataAvailableListener<EnergyLevel> listener = (data) -> { if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) { float rangeRemaining = data.getRangeRemainingMeters().getValue(); } else { // Handle error } }; carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carInfo.removeEnergyLevelListener(listener);
لا تفترض أنّ البيانات من السيارة متاحة في جميع الأوقات.
في حال حدوث خطأ، تحقَّق من الحالة الخاصة بالقيمة التي طلبتها لمعرفة سبب تعذّر استرداد البيانات المطلوبة. راجِع المستندات المرجعية لمعرفة تعريف فئة CarInfo
الكامل.
CarSensors
يتيح لك الصف CarSensors
الوصول إلى بيانات مقياس التسارع والجيروسكوب والبوصلة والموقع الجغرافي الخاصة بالمركبة. وقد يعتمد مدى توفّر هذه القيم على الشركة المصنّعة للجهاز الأصلي. يكون تنسيق البيانات الواردة من مقياس التسارع والجيروسكوب والبوصلة هو نفسه التنسيق الذي تحصل عليه من واجهة برمجة التطبيقات SensorManager
. على سبيل المثال،
للتحقّق من اتجاه المركبة:
Kotlin
val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors val listener = OnCarDataAvailableListener<Compass> { data -> if (data.orientations.status == CarValue.STATUS_SUCCESS) { val orientation = data.orientations.value } else { // Data not available, handle error } } carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener) … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener)
Java
CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors(); OnCarDataAvailableListener<Compass> listener = (data) -> { if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) { List<Float> orientations = data.getOrientations().getValue(); } else { // Data not available, handle error } }; carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(), listener); … // Unregister the listener when you no longer need updates carSensors.removeCompassListener(listener);
للوصول إلى بيانات الموقع الجغرافي من السيارة، عليك أيضًا الإفصاح عن إذن android.permission.ACCESS_FINE_LOCATION
وطلبه.
الاختبار
لمحاكاة بيانات المستشعر عند الاختبار على Android Auto، يُرجى الرجوع إلى قسمَي أجهزة الاستشعار وإعدادات أجهزة الاستشعار في دليل "وحدة رأسية على الكمبيوتر". لمحاكاة بيانات المستشعر عند الاختبار على نظام التشغيل Android Automotive، يُرجى الرجوع إلى قسم محاكاة حالة الأجهزة في دليل محاكي Android Automotive.
دورات حياة CarAppService والجلسة والشاشة
تنفّذ الفئتان Session
وScreen
الواجهة LifecycleOwner
. أثناء تفاعل المستخدم مع التطبيق، يتم استدعاء عمليات معاودة الاتصال الخاصة بدورة حياة العنصرَين Session
وScreen
، كما هو موضّح في المخططات التالية.
دورات حياة CarAppService وSession

Session
دورة الحياةللاطّلاع على التفاصيل الكاملة، راجِع مستندات طريقة
Session.getLifecycle
.
مراحل نشاط الشاشة

Screen
دورة الحياةلمعرفة التفاصيل الكاملة، يُرجى الاطّلاع على مستندات طريقة
Screen.getLifecycle
.
التسجيل من ميكروفون السيارة
باستخدام CarAppService
في تطبيقك وواجهة برمجة التطبيقات CarAudioRecord
، يمكنك منح تطبيقك إذن الوصول إلى ميكروفون السيارة. على المستخدمين منح تطبيقك الإذن بالوصول إلى ميكروفون السيارة. يمكن لتطبيقك تسجيل مدخلات المستخدم ومعالجتها داخل التطبيق.
إذن التسجيل
قبل تسجيل أي صوت، عليك أولاً توضيح إذن التسجيل في AndroidManifest.xml
وطلب أن يمنحه المستخدم.
<manifest ...>
...
<uses-permission android:name="android.permission.RECORD_AUDIO" />
...
</manifest>
يجب طلب الإذن بالتسجيل في وقت التشغيل. راجِع قسم طلب الأذونات للحصول على تفاصيل حول كيفية طلب إذن في تطبيق السيارة.
تسجيل الصوت
بعد أن يمنح المستخدم الإذن بالتسجيل، يمكنك تسجيل الصوت ومعالجة التسجيل.
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) carAudioRecord.startRecording() val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording()
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); carAudioRecord.startRecording(); byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE]; while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) { // Use data array // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech } carAudioRecord.stopRecording();
التركيز على الصوت
عند التسجيل باستخدام ميكروفون السيارة، يجب أولاً الحصول على إذن استخدام الصوت لضمان إيقاف أي وسائط قيد التشغيل. إذا فقدت التركيز الصوتي، توقّف عن التسجيل.
في ما يلي مثال على كيفية الحصول على تركيز الصوت:
Kotlin
val carAudioRecord = CarAudioRecord.create(carContext) // Take audio focus so that user's media is not recorded val audioAttributes = AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build() val audioFocusRequest = AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener { state: Int -> if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording() } } .build() if (carContext.getSystemService(AudioManager::class.java) .requestAudioFocus(audioFocusRequest) != AudioManager.AUDIOFOCUS_REQUEST_GRANTED ) { // Don't record if the focus isn't granted return } carAudioRecord.startRecording() // Process the audio and abandon the AudioFocusRequest when done
Java
CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext()); // Take audio focus so that user's media is not recorded AudioAttributes audioAttributes = new AudioAttributes.Builder() .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH) // Use the most appropriate usage type for your use case .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE) .build(); AudioFocusRequest audioFocusRequest = new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE) .setAudioAttributes(audioAttributes) .setOnAudioFocusChangeListener(state -> { if (state == AudioManager.AUDIOFOCUS_LOSS) { // Stop recording if audio focus is lost carAudioRecord.stopRecording(); } }) .build(); if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest) != AUDIOFOCUS_REQUEST_GRANTED) { // Don't record if the focus isn't granted return; } carAudioRecord.startRecording(); // Process the audio and abandon the AudioFocusRequest when done
مكتبة الاختبارات
توفّر مكتبة
الاختبار في Android for Cars فئات مساعدة يمكنك استخدامها للتحقّق من صحة سلوك تطبيقك في بيئة اختبار.
على سبيل المثال، يتيح لك
SessionController
محاكاة عملية ربط بالمضيف والتأكّد من إنشاء
Screen
و
Template
بشكل صحيح وعرضهما.
راجِع العينات للاطّلاع على أمثلة حول الاستخدام.
الإبلاغ عن مشكلة في "مكتبة تطبيقات Android للسيارات"
إذا واجهت مشكلة في المكتبة، يُرجى الإبلاغ عنها باستخدام أداة تتبُّع المشاكل في Google. احرص على ملء جميع المعلومات المطلوبة في نموذج المشكلة.
قبل تسجيل مشكلة جديدة، يُرجى التحقّق مما إذا كانت مُدرَجة في ملاحظات الإصدار الخاصة بالمكتبة أو تم الإبلاغ عنها في قائمة المشاكل. يمكنك الاشتراك في المشاكل والتصويت عليها من خلال النقر على النجمة الخاصة بمشكلة في أداة التتبُّع. لمزيد من المعلومات، اطّلِع على مقالة الاشتراك في مشكلة.