از کتابخانه برنامه Android for Cars استفاده کنید

کتابخانه برنامه Android for Cars به ​​شما امکان می دهد برنامه های ناوبری، نقطه مورد علاقه (POI) و اینترنت اشیا (IOT) خود را به ماشین بیاورید. این کار را با ارائه مجموعه‌ای از الگوهای طراحی شده برای مطابقت با استانداردهای حواس‌پرتی راننده و مراقبت از جزئیاتی مانند انواع فاکتورهای صفحه نمایش خودرو و روش‌های ورودی انجام می‌دهد.

این راهنما نمای کلی از ویژگی‌ها و مفاهیم کلیدی کتابخانه را ارائه می‌کند و شما را در فرآیند راه‌اندازی یک برنامه اولیه راهنمایی می‌کند.

قبل از شروع
  1. صفحات طراحی برای رانندگی را که کتابخانه برنامه ماشین را پوشش می دهد، مرور کنید
  2. اصطلاحات و مفاهیم کلیدی را در بخش زیر مرور کنید.
  3. با رابط کاربری Android Auto System و طراحی سیستم عامل Android Automotive آشنا شوید.
  4. یادداشت های انتشار را مرور کنید.
  5. نمونه ها را مرور کنید.
اصطلاحات و مفاهیم کلیدی
مدل ها و قالب ها
رابط کاربری با نموداری از اشیاء مدل نشان داده می‌شود که می‌توانند به روش‌های مختلف با هم مرتب شوند، همانطور که توسط قالبی که به آن تعلق دارند مجاز است. قالب ها زیرمجموعه ای از مدل ها هستند که می توانند به عنوان ریشه در آن نمودارها عمل کنند. مدل‌ها شامل اطلاعاتی هستند که در قالب متن و تصویر به کاربر نمایش داده می‌شوند و همچنین ویژگی‌هایی برای پیکربندی جنبه‌های ظاهر بصری چنین اطلاعاتی - برای مثال رنگ‌های متن یا اندازه‌های تصویر. میزبان مدل ها را به نماهایی تبدیل می کند که برای مطابقت با استانداردهای حواس پرتی راننده طراحی شده اند و از جزئیاتی مانند انواع فاکتورهای صفحه نمایش خودرو و روش های ورودی مراقبت می کند.
میزبان
میزبان جزء پشتیبان است که عملکرد ارائه شده توسط APIهای کتابخانه را پیاده سازی می کند تا برنامه شما بتواند در ماشین اجرا شود. مسئولیت‌های میزبان از کشف برنامه شما و مدیریت چرخه عمر آن گرفته تا تبدیل مدل‌های شما به نماها و اطلاع‌رسانی به برنامه شما از تعاملات کاربر متغیر است. در دستگاه های تلفن همراه، این میزبان توسط Android Auto پیاده سازی شده است. در سیستم عامل Android Automotive، این میزبان به عنوان یک برنامه سیستمی نصب شده است.
محدودیت های قالب
قالب های مختلف محدودیت هایی را در محتوای مدل های خود اعمال می کنند. به عنوان مثال، قالب‌های فهرست محدودیت‌هایی در تعداد مواردی دارند که می‌توانند به کاربر ارائه شوند. الگوها همچنین محدودیت هایی در نحوه اتصال آنها برای شکل دادن به جریان یک کار دارند. به عنوان مثال، این برنامه تنها می تواند تا پنج الگو را به پشته صفحه نمایش دهد. برای جزئیات بیشتر به محدودیت های الگو مراجعه کنید.
Screen
Screen کلاسی است که توسط کتابخانه ارائه می شود که برنامه ها برای مدیریت رابط کاربری ارائه شده به کاربر پیاده سازی می کنند. یک Screen یک چرخه حیات دارد و مکانیزمی را برای برنامه برای ارسال الگو برای نمایش زمانی که صفحه نمایش قابل مشاهده است فراهم می کند. نمونه های Screen همچنین می توانند به پشته Screen نمایش داده شوند و از آن خارج شوند، که تضمین می کند آنها به محدودیت های جریان الگو پایبند هستند.
CarAppService
CarAppService یک کلاس Service انتزاعی است که برنامه شما باید آن را پیاده سازی و صادر کند تا توسط میزبان کشف و مدیریت شود. CarAppService برنامه شما مسئول تأیید اعتبار اتصال میزبان با استفاده از createHostValidator است و متعاقباً با استفاده از onCreateSession نمونه‌های Session را برای هر اتصال ارائه می‌کند.
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 خود را همانطور که در بخش قبل توضیح داده شد، با اضافه کردن یک یا چند مورد از مقادیر دسته زیر در فیلتر intent، دسته برنامه خود را اعلام کنید:

  • androidx.car.app.category.NAVIGATION : برنامه ای که مسیرهای ناوبری را به صورت گام به گام ارائه می دهد. برای مستندات بیشتر در مورد این دسته ، برنامه‌های ناوبری ساخت خودرو را بررسی کنید.
  • androidx.car.app.category.POI : برنامه ای که عملکردهای مرتبط با یافتن نقاط مورد علاقه مانند مکان های پارکینگ، ایستگاه های شارژ و پمپ بنزین را ارائه می دهد. برای مستندات بیشتر در مورد این دسته، برنامه های Build point of interest برای اتومبیل ها را بررسی کنید.
  • androidx.car.app.category.IOT : برنامه ای که کاربران را قادر می سازد تا اقدامات مربوطه را در دستگاه های متصل از داخل خودرو انجام دهند. برای مستندات بیشتر در مورد این دسته، برنامه های Build internet of things برای اتومبیل ها را بررسی کنید.

برای توضیحات دقیق هر دسته و معیارهای مربوط به برنامه‌ها، کیفیت برنامه اندروید برای خودروها را ببینید.

نام و نماد برنامه را مشخص کنید

باید نام و نماد برنامه را مشخص کنید که میزبان بتواند از آن برای نشان دادن برنامه شما در رابط کاربری سیستم استفاده کند.

می‌توانید با استفاده از 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>
سطح API برنامه Car

Car App Library سطوح API خود را تعریف می‌کند تا بتوانید بدانید کدام ویژگی‌های کتابخانه توسط میزبان الگو در خودرو پشتیبانی می‌شود. برای بازیابی بالاترین سطح API Car App پشتیبانی شده توسط یک میزبان، از متد getCarAppApiLevel() استفاده کنید.

حداقل سطح API Car App را که توسط برنامه شما پشتیبانی می شود در فایل AndroidManifest.xml خود اعلام کنید:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

برای جزئیات بیشتر در مورد نحوه حفظ سازگاری به عقب و اعلام حداقل سطح API مورد نیاز برای استفاده از یک ویژگی، به مستندات حاشیه نویسی RequiresCarApi مراجعه کنید. برای تعریف اینکه کدام سطح API برای استفاده از ویژگی خاصی از کتابخانه برنامه خودرو لازم است، مستندات مرجع CarAppApiLevels را بررسی کنید.

CarAppService و Session خود را ایجاد کنید

برنامه شما باید کلاس CarAppService را گسترش دهد و روش onCreateSession خود را پیاده سازی کند، که نمونه Session مربوط به اتصال فعلی به هاست را برمی گرداند:

کاتلین
class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}
جاوا
public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

نمونه Session مسئول برگرداندن نمونه Screen برای استفاده از اولین بار شروع برنامه است:

کاتلین
class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen(carContext)
    }
    ...
}
جاوا
public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen(getCarContext());
    }
    ...
}

برای رسیدگی به سناریوهایی که برنامه ماشین شما باید از صفحه‌ای شروع شود که صفحه اصلی یا صفحه اصلی برنامه شما نیست، مانند مدیریت پیوندهای عمیق، می‌توانید قبل از بازگشت از onCreateScreen ، پشته‌ای از صفحه‌ها را با استفاده از ScreenManager.push پیش‌بینی کنید. Pre-seeding به کاربران امکان می دهد از اولین صفحه ای که برنامه شما نشان می دهد به صفحه های قبلی برگردند.

صفحه شروع خود را ایجاد کنید

شما صفحات نمایش داده شده توسط برنامه خود را با تعریف کلاس هایی ایجاد می کنید که کلاس Screen را گسترش می دهند و روش onGetTemplate آن را پیاده سازی می کند، که نمونه Template را نشان دهنده وضعیت رابط کاربری برای نمایش در صفحه ماشین برمی گرداند.

قطعه زیر نشان می دهد که چگونه می توان Screen اعلام کرد که از یک الگوی PaneTemplate برای نمایش یک "Hello world!" ساده استفاده می کند. رشته:

کاتلین
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()
    }
}
جاوا
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 همچنین قابلیت‌های دیگری را ارائه می‌کند، مانند اینکه به شما اجازه می‌دهد منابع قابل ترسیم را با استفاده از پیکربندی از صفحه ماشین بارگیری کنید، برنامه‌ای را در ماشین با استفاده از intent راه‌اندازی کنید ، و نشان دهید که آیا برنامه شما باید نقشه‌اش را با تم تیره نمایش دهد یا خیر.

پیاده سازی ناوبری صفحه

برنامه‌ها اغلب صفحه‌های مختلفی را ارائه می‌دهند، که هر کدام احتمالاً از الگوهای مختلفی استفاده می‌کنند که کاربر می‌تواند در تعامل با رابط نمایش داده شده در صفحه، در میان آنها حرکت کند.

کلاس ScreenManager یک پشته صفحه نمایش را ارائه می دهد که می توانید از آن برای فشار دادن صفحه نمایش ها استفاده کنید که می تواند به طور خودکار هنگامی که کاربر دکمه برگشت را در صفحه ماشین انتخاب می کند یا از دکمه سخت افزاری برگشت موجود در برخی از اتومبیل ها استفاده می کند ظاهر شود.

قطعه زیر نشان می دهد که چگونه می توان یک اکشن برگشتی را به یک الگوی پیام اضافه کرد و همچنین عملکردی را نشان می دهد که هنگام انتخاب کاربر، صفحه جدیدی را فشار می دهد:

کاتلین
val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()
جاوا
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.invalidate درخواست کند محتوای یک Screen را باطل کند. میزبان متعاقباً با روش Screen.onGetTemplate برنامه شما تماس می گیرد تا الگو را با محتویات جدید بازیابی کند.

هنگام بازخوانی یک Screen ، مهم است که محتوای خاصی را در قالب درک کنید که می‌تواند به‌روزرسانی شود، بنابراین میزبان، الگوی جدید را در سهمیه الگو به حساب نمی‌آورد. برای جزئیات بیشتر به بخش محدودیت های الگو مراجعه کنید.

توصیه می‌کنیم صفحه‌های خود را طوری ساختار دهید که یک نگاشت یک به یک بین یک Screen و نوع قالبی که از طریق اجرای onGetTemplate آن برمی‌گرداند وجود داشته باشد.

ترسیم نقشه ها

برنامه‌های ناوبری و نقاط مورد علاقه (POI) با استفاده از الگوهای زیر می‌توانند با دسترسی به یک Surface نقشه‌ها را ترسیم کنند:

الگو مجوز قالب راهنمایی دسته
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES ناوبری
MapWithContentTemplate androidx.car.app.NAVIGATION_TEMPLATES یا
androidx.car.app.MAP_TEMPLATES
ناوبری ، POI
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() ارسال می‌شود.

کاتلین
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
جاوا
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
ناحیه قابل مشاهده سطح را درک کنید

میزبان می تواند عناصر رابط کاربری را برای الگوهای بالای نقشه بکشد. میزبان با فراخوانی متد SurfaceCallback.onVisibleAreaChanged ، ناحیه‌ای از سطح را که تضمین شده است بدون مانع و کاملاً برای کاربر قابل مشاهده است، ارتباط برقرار می‌کند. همچنین برای به حداقل رساندن تعداد تغییرات، میزبان متد SurfaceCallback.onStableAreaChanged را با کوچکترین مستطیل فراخوانی می کند که همیشه بر اساس الگوی فعلی قابل مشاهده است.

به عنوان مثال، هنگامی که یک برنامه ناوبری از NavigationTemplate با یک نوار اقدام در بالا استفاده می کند، زمانی که کاربر برای مدتی با صفحه تعامل نداشته باشد، نوار اقدام می تواند خود را پنهان کند تا فضای بیشتری برای نقشه ایجاد کند. در این حالت، یک تماس به onStableAreaChanged و onVisibleAreaChanged با همان مستطیل وجود دارد. وقتی نوار اقدام پنهان است، فقط onVisibleAreaChanged با ناحیه بزرگتر فراخوانی می شود. اگر کاربر با صفحه تعامل داشته باشد، دوباره فقط onVisibleAreaChanged با اولین مستطیل فراخوانی می شود.

پشتیبانی از تم تیره

برنامه‌ها باید نقشه خود را روی نمونه Surface با رنگ‌های تیره مناسب، زمانی که میزبان تعیین می‌کند، آن‌طور که در کیفیت برنامه Android برای خودروها توضیح داده شده است، دوباره ترسیم کنند.

برای تصمیم گیری در مورد ترسیم نقشه تاریک، می توانید از روش CarContext.isDarkMode استفاده کنید. هر زمان که وضعیت تم تیره تغییر کند، با Session.onCarConfigurationChanged تماسی دریافت می‌کنید.

به کاربران اجازه دهید با نقشه شما تعامل داشته باشند

هنگام استفاده از الگوهای زیر، می‌توانید برای تعامل کاربران با نقشه‌هایی که ترسیم می‌کنید، پشتیبانی اضافه کنید، مانند اینکه به آن‌ها اجازه دهید قسمت‌های مختلف نقشه را با بزرگ‌نمایی و جابجایی ببینند.

الگو تعامل از سطح API برنامه Car پشتیبانی می شود
NavigationTemplate 2
PlaceListNavigationTemplate ( منسوخ شده ) 4
RoutePreviewNavigationTemplate ( منسوخ شده ) 4
MapTemplate ( منسوخ شده ) 5 (معرفی قالب)
MapWithContentTemplate 7 (معرفی قالب)
اجرای تماس های تعاملی

رابط SurfaceCallback چندین روش پاسخ به تماس دارد که می‌توانید برای افزودن تعامل به نقشه‌های ساخته شده با الگوهای بخش قبل پیاده‌سازی کنید:

تعامل روش SurfaceCallback از سطح API برنامه Car پشتیبانی می شود
ضربه بزنید onClick 5
برای بزرگنمایی، خرج کردن onScale 2
کشیدن تک لمسی onScroll 2
پرتاب تک لمسی onFling 2
دو ضربه سریع بزنید onScale (با ضریب مقیاس تعیین شده توسط میزبان الگو) 2
حرکت چرخشی در حالت پان onScroll (با فاکتور فاصله تعیین شده توسط میزبان الگو) 2
یک نوار اقدام نقشه اضافه کنید

این الگوها می‌توانند یک نوار عملکرد نقشه برای اقدامات مرتبط با نقشه مانند بزرگنمایی و کوچک‌نمایی، نمایش مجدد قطب‌نما و سایر اقداماتی که برای نمایش انتخاب می‌کنید داشته باشند. نوار اکشن نقشه می‌تواند تا چهار دکمه فقط دارای نماد داشته باشد که می‌توانند بدون تأثیر بر عمق کار، به‌روزرسانی شوند. در حالت بیکار پنهان می شود و در حالت فعال دوباره ظاهر می شود.

برای دریافت تماس‌های تعاملی نقشه، باید یک دکمه Action.PAN را در نوار اقدام نقشه اضافه کنید. هنگامی که کاربر دکمه پان را فشار می دهد، میزبان وارد حالت پان می شود، همانطور که در قسمت زیر توضیح داده شده است.

اگر برنامه شما دکمه Action.PAN را در نوار اقدام نقشه حذف کند، ورودی کاربر را از روش‌های SurfaceCallback دریافت نمی‌کند و میزبان از حالت پان که قبلاً فعال شده است خارج می‌شود.

در صفحه لمسی، دکمه پان نمایش داده نمی شود.

حالت پان را درک کنید

در حالت پان، میزبان الگو ورودی های کاربر را از دستگاه های ورودی غیر لمسی، مانند کنترلرهای چرخشی و پد لمسی، به روش های SurfaceCallback مناسب ترجمه می کند. به اقدام کاربر برای ورود یا خروج از حالت پان با متد setPanModeListener در NavigationTemplate.Builder پاسخ دهید. وقتی کاربر در حالت پان است، میزبان می‌تواند سایر اجزای رابط کاربری را در قالب پنهان کند.

با کاربر تعامل داشته باشید

برنامه شما می تواند با استفاده از الگوهای مشابه یک برنامه تلفن همراه با کاربر تعامل داشته باشد.

کنترل ورودی کاربر

برنامه شما می‌تواند با ارسال شنوندگان مناسب به مدل‌هایی که از آنها پشتیبانی می‌کنند، به ورودی‌های کاربر پاسخ دهد. قطعه زیر نحوه ایجاد یک Action Model را نشان می دهد که یک OnClickListener را تنظیم می کند که متدی را که توسط کد برنامه شما تعریف شده است، فراخوانی می کند:

کاتلین
val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()
جاوا
Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

سپس روش onClickNavigate می‌تواند برنامه پیش‌فرض ماشین ناوبری را با استفاده از روش CarContext.startCarApp راه‌اندازی کند:

کاتلین
private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}
جاوا
private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

برای جزئیات بیشتر درباره نحوه راه‌اندازی برنامه‌ها، از جمله قالب هدف ACTION_NAVIGATE ، به بخش Start a car with a intent مراجعه کنید.

برخی از اقدامات، مانند اقداماتی که نیاز به هدایت کاربر برای ادامه تعامل در دستگاه های تلفن همراه خود دارند، تنها زمانی مجاز هستند که خودرو پارک شده باشد. برای اجرای این اقدامات می توانید از ParkedOnlyOnClickListener استفاده کنید. اگر ماشین پارک نشده باشد، میزبان نشانه ای را به کاربر نشان می دهد که در این مورد عمل مجاز نیست. اگر ماشین پارک شده باشد، کد به طور معمول اجرا می شود. قطعه زیر نحوه استفاده از ParkedOnlyOnClickListener را برای باز کردن صفحه تنظیمات در دستگاه تلفن همراه نشان می دهد:

کاتلین
val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()
جاوا
Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();
نمایش اعلان ها

اعلان‌های ارسال شده به دستگاه تلفن همراه تنها در صورتی روی صفحه ماشین نشان داده می‌شوند که با CarAppExtender گسترش داده شوند. برخی از ویژگی‌های اعلان، مانند عنوان محتوا، متن، نماد و کنش‌ها را می‌توان در CarAppExtender تنظیم کرد و ویژگی‌های اعلان را هنگامی که روی صفحه ماشین ظاهر می‌شوند لغو کرد.

قطعه زیر نحوه ارسال اعلان به صفحه ماشین را نشان می دهد که عنوانی متفاوت از عنوان نشان داده شده در دستگاه تلفن همراه را نشان می دهد:

کاتلین
val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()
جاوا
Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

اعلان ها می توانند بخش های زیر از رابط کاربری را تحت تاثیر قرار دهند:

  • ممکن است یک اعلان heads-up (HUN) به کاربر نمایش داده شود.
  • ممکن است یک ورودی در مرکز اعلان اضافه شود، که به صورت اختیاری یک نشان قابل مشاهده در راه آهن است.
  • برای برنامه های ناوبری، اعلان ممکن است در ویجت راه آهن همانطور که در اعلان های مرحله به مرحله توضیح داده شده است، نمایش داده شود.

همانطور که در مستندات CarAppExtender توضیح داده شده است، می توانید نحوه پیکربندی اعلان های برنامه خود را برای تأثیرگذاری بر هر یک از آن عناصر رابط کاربری با استفاده از اولویت اعلان انتخاب کنید.

اگر NotificationCompat.Builder.setOnlyAlertOnce با مقدار true فراخوانی شود، یک اعلان با اولویت بالا تنها یک بار به صورت HUN نمایش داده می شود.

برای اطلاعات بیشتر در مورد نحوه طراحی اعلان‌های برنامه خودرو، به راهنمای Google Design for Driving درباره اعلان‌ها مراجعه کنید.

نان تست را نشان دهید

همانطور که در این قطعه نشان داده شده است، برنامه شما می تواند با استفاده CarToast یک نان تست را نمایش دهد:

کاتلین
CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()
جاوا
CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();
درخواست مجوزها

اگر برنامه شما نیاز به دسترسی به داده‌ها یا اقدامات محدود شده دارد (مثلاً مکان)، قوانین استاندارد مجوزهای Android اعمال می‌شود. برای درخواست مجوز، می توانید از متد CarContext.requestPermissions() استفاده کنید.

مزیت استفاده از CarContext.requestPermissions() ، بر خلاف استفاده از APIهای استاندارد 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 را فراخوانی کنید:

  • شماره گیر را برای برقراری تماس تلفنی باز کنید.
  • پیمایش گام به گام را به یک مکان با برنامه پیش‌فرض ماشین ناوبری شروع کنید.
  • برنامه خود را با یک هدف راه اندازی کنید.

مثال زیر نحوه ایجاد اعلان را با عملکردی که برنامه شما را با صفحه‌ای که جزئیات رزرو پارکینگ را نشان می‌دهد باز می‌کند، نشان می‌دهد. شما نمونه اعلان را با هدف محتوایی گسترش می دهید که حاوی یک PendingIntent است که یک هدف صریح را به عملکرد برنامه شما می بندد:

کاتلین
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())
جاوا
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 با هدف شامل URI داده فراخوانی می کند:

کاتلین
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)))
        }
    }
}
جاوا
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 در برنامه شما با فشار دادن صفحه رزرو پارکینگ در پشته، این هدف را کنترل می‌کند، در صورتی که قبلاً در بالای صفحه نیست:

کاتلین
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))
        }
    }
}
جاوا
@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()));
        }
    }
}

برای اطلاعات بیشتر در مورد نحوه رسیدگی به اعلان‌ها برای برنامه ماشین، بخش نمایش اعلان‌ها را ببینید.

محدودیت های قالب

میزبان تعداد الگوهایی را برای نمایش برای یک کار معین به حداکثر 5 عدد محدود می کند که آخرین الگو باید یکی از انواع زیر باشد:

توجه داشته باشید که این محدودیت برای تعداد الگوها اعمال می شود و نه تعداد نمونه های Screen در پشته. به عنوان مثال، اگر یک برنامه در حالی که در صفحه A است، دو الگو ارسال کند و سپس صفحه B را فشار دهد، اکنون می تواند سه الگوی دیگر ارسال کند. متناوبا، اگر ساختار هر صفحه برای ارسال یک الگو باشد، برنامه می‌تواند پنج نمونه صفحه را در پشته ScreenManager قرار دهد.

موارد خاصی برای این محدودیت ها وجود دارد: بازخوانی قالب و عملیات بازگشت و بازنشانی.

قالب به روز می شود

برخی از به‌روزرسانی‌های محتوایی در محدودیت قالب حساب نمی‌شوند. به طور کلی، اگر یک برنامه یک الگوی جدید را که از همان نوع است و حاوی محتوای اصلی قالب قبلی است را فشار دهد، الگوی جدید در سهمیه حساب نمی‌شود. به عنوان مثال، به‌روزرسانی وضعیت جابجایی یک ردیف در یک ListTemplate در سهمیه حساب نمی‌شود. برای آشنایی بیشتر با انواع به‌روزرسانی‌های محتوا، به مستندات تک تک قالب‌ها مراجعه کنید.

عملیات پشت

برای فعال کردن جریان‌های فرعی در یک کار، میزبان تشخیص می‌دهد که یک برنامه در حال نمایش یک Screen از پشته ScreenManager است و سهمیه باقی‌مانده را بر اساس تعداد الگوهایی که برنامه به عقب برمی‌گردد، به‌روزرسانی می‌کند.

برای مثال، اگر برنامه در حالی که در صفحه A است، دو الگو ارسال کند، سپس صفحه B را فشار دهد و دو الگوی دیگر ارسال کند، برنامه یک سهمیه باقی مانده است. اگر برنامه به صفحه A بازگردد، میزبان سهمیه را به سه بازنشانی می‌کند، زیرا برنامه با دو الگو به عقب رفته است.

توجه داشته باشید که زمانی که یک برنامه به صفحه نمایش باز می گردد، باید یک الگو را ارسال کند که از همان نوع قالبی باشد که آخرین بار توسط آن صفحه ارسال شده است. ارسال هر نوع قالب دیگری باعث ایجاد خطا می شود. با این حال، تا زمانی که نوع آن در طول عملیات برگشت یکسان باقی بماند، یک برنامه می‌تواند آزادانه محتویات الگو را بدون تأثیر بر سهمیه تغییر دهد.

بازنشانی عملیات

برخی از الگوها دارای معنای خاصی هستند که به معنای پایان یک کار است. به عنوان مثال، NavigationTemplate یک نمای است که انتظار می رود روی صفحه باقی بماند و با دستورالعمل های گام به گام جدید برای مصرف کاربر به روز شود. هنگامی که به یکی از این الگوها می رسد، میزبان سهمیه الگو را بازنشانی می کند و با آن الگو به گونه ای رفتار می کند که گویی اولین مرحله از یک کار جدید است. این به برنامه اجازه می دهد تا یک کار جدید را شروع کند. به مستندات تک تک الگوها مراجعه کنید تا ببینید کدام یک بازنشانی را در میزبان ایجاد می کنند.

اگر میزبان قصد شروع برنامه را از طریق یک اقدام اعلان یا از راه‌انداز دریافت کند، سهمیه نیز بازنشانی می‌شود. این مکانیسم به برنامه اجازه می‌دهد تا یک کار جدید را از اعلان‌ها شروع کند، و حتی اگر برنامه‌ای از قبل محدود شده باشد و در پیش‌زمینه باشد، صادق است.

برای جزئیات بیشتر در مورد نحوه نمایش اعلان‌های برنامه خود در صفحه ماشین، به بخش نمایش اعلان‌ها مراجعه کنید. برای اطلاعات در مورد نحوه راه‌اندازی برنامه از طریق یک اقدام اعلان، به بخش Start a car with a intent مراجعه کنید.

اتصال API

با استفاده از CarConnection API برای بازیابی اطلاعات اتصال در زمان اجرا، می توانید تعیین کنید که آیا برنامه شما روی Android Auto یا Android Automotive OS اجرا می شود.

به عنوان مثال، در Session برنامه خودروی خود، CarConnection را راه‌اندازی کنید و در به‌روزرسانی‌های LiveData مشترک شوید:

کاتلین
CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)
جاوا
new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);

در مشاهده گر، می توانید به تغییرات در وضعیت اتصال واکنش نشان دهید:

کاتلین
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()
}
جاوا
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();
}
محدودیت‌های API

ماشین‌های مختلف ممکن است اجازه دهند تعداد متفاوتی از نمونه‌های Item در یک زمان به کاربر نمایش داده شود. از ConstraintManager برای بررسی محدودیت محتوا در زمان اجرا استفاده کنید و تعداد مناسبی از موارد را در قالب‌های خود تنظیم کنید.

با گرفتن ConstraintManager از CarContext شروع کنید:

کاتلین
val manager = carContext.getCarService(ConstraintManager::class.java)
جاوا
ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

سپس می توانید شی ConstraintManager بازیابی شده را برای محدودیت محتوای مربوطه پرس و جو کنید. به عنوان مثال، برای به دست آوردن تعداد مواردی که می توان در یک شبکه نمایش داد، getContentLimit با CONTENT_LIMIT_TYPE_GRID تماس بگیرید:

کاتلین
val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)
جاوا
int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);
یک جریان ورود به سیستم اضافه کنید

اگر برنامه شما تجربه ورود به سیستم را برای کاربران ارائه می‌دهد، می‌توانید از الگوهایی مانند SignInTemplate و LongMessageTemplate با Car App API سطح 2 و بالاتر برای ورود به برنامه خود در قسمت اصلی خودرو استفاده کنید.

برای ایجاد یک SignInTemplate ، یک SignInMethod تعریف کنید. کتابخانه برنامه خودرو در حال حاضر از روش‌های ورود به سیستم زیر پشتیبانی می‌کند:

  • InputSignInMethod برای ورود نام کاربری/رمز عبور.
  • PinSignInMethod برای ورود به سیستم پین، که در آن کاربر با استفاده از یک پین نمایش داده شده روی واحد اصلی، حساب خود را از تلفن خود پیوند می دهد.
  • ProviderSignInMethod برای ورود به سیستم ارائه دهنده، مانند Google Sign-In و One Tap .
  • QRCodeSignInMethod برای ورود به سیستم کد QR، جایی که کاربر یک کد QR را اسکن می کند تا ورود به سیستم را در تلفن خود کامل کند. این با Car API سطح 4 و بالاتر در دسترس است.

به عنوان مثال، برای پیاده سازی قالبی که رمز عبور کاربر را جمع آوری می کند، با ایجاد یک InputCallback برای پردازش و اعتبارسنجی ورودی کاربر شروع کنید:

کاتلین
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.
    }
}
جاوا
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 مورد نیاز است.

کاتلین
val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()
جاوا
InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

در نهایت، از InputSignInMethod جدید خود برای ایجاد یک SignInTemplate استفاده کنید.

کاتلین
SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()
جاوا
new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();
از AccountManager استفاده کنید

برنامه‌های سیستم‌عامل Android Automotive که دارای احراز هویت هستند، به دلایل زیر باید از AccountManager استفاده کنند:

  • تجربه کاربری بهتر و سهولت مدیریت حساب : کاربران می توانند به راحتی تمام حساب های خود را از منوی حساب ها در تنظیمات سیستم مدیریت کنند، از جمله ورود به سیستم و خروج از سیستم.
  • تجربه‌های «مهمان» : از آنجایی که خودروها دستگاه‌های مشترک هستند، OEM‌ها می‌توانند تجربه‌های مهمان را در خودرو فعال کنند، جایی که نمی‌توان حساب‌ها را اضافه کرد.
انواع رشته متن را اضافه کنید

اندازه های مختلف صفحه نمایش ماشین ممکن است مقادیر متفاوتی از متن را نشان دهد. با Car App API سطح 2 و بالاتر، می‌توانید انواع مختلفی از یک رشته متنی را مشخص کنید تا به بهترین نحو با صفحه نمایش مطابقت داشته باشد. برای دیدن مکان‌هایی که انواع متن پذیرفته می‌شوند، به دنبال الگوها و مؤلفه‌هایی باشید که CarText را می‌گیرند.

می توانید انواع رشته متنی را با متد CarText.Builder.addVariant() به CarText اضافه کنید:

کاتلین
val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()
جاوا
CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

سپس می توانید از این CarText - برای مثال، به عنوان متن اصلی GridItem استفاده کنید.

کاتلین
GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()
جاوا
new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

رشته ها را به ترتیب از بیشترین به کمترین ترجیح اضافه کنید - برای مثال، از طولانی ترین به کوتاه ترین. میزبان رشته با طول مناسب را بسته به میزان فضای موجود روی صفحه ماشین انتخاب می کند.

CarIcon های درون خطی را برای ردیف ها اضافه کنید

با استفاده از CarIconSpan می‌توانید نمادهایی را به صورت متنی اضافه کنید تا جذابیت بصری برنامه خود را تقویت کنید. برای اطلاعات بیشتر در مورد ایجاد این دهانه ها به مستندات CarIconSpan.create مراجعه کنید. برای یک نمای کلی از نحوه عملکرد استایل نوشتار با دهانه ، استایل‌سازی متن Spantastic با Spans را ببینید.

کاتلین
  
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()
  
  
جاوا
  
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();
  
  
API های سخت افزار خودرو

با شروع API سطح 3 Car App، کتابخانه برنامه Car دارای APIهایی است که می توانید از آنها برای دسترسی به ویژگی ها و حسگرهای خودرو استفاده کنید.

الزامات

برای استفاده از APIها با Android Auto، با افزودن یک وابستگی به androidx.car.app:app-projected به فایل build.gradle ماژول Android Auto خود شروع کنید. برای سیستم عامل Android Automotive، یک وابستگی به androidx.car.app:app-automotive به فایل build.gradle ماژول سیستم عامل Android Automotive خود اضافه کنید.

علاوه بر این، در فایل AndroidManifest.xml خود، باید مجوزهای مربوطه مورد نیاز برای درخواست داده‌های خودرویی را که می‌خواهید استفاده کنید، اعلام کنید . توجه داشته باشید که این مجوزها نیز باید توسط کاربر به شما اعطا شود. می‌توانید از همان کد در Android Auto و Android Automotive OS استفاده کنید، نه اینکه مجبور باشید جریان‌های وابسته به پلتفرم ایجاد کنید. با این حال، مجوزهای مورد نیاز متفاوت است.

CarInfo

این جدول ویژگی های ظاهر شده توسط API های CarInfo و مجوزهایی را که برای استفاده از آنها باید درخواست کنید، توضیح می دهد:

روش ها خواص مجوزهای Android Auto مجوزهای سیستم عامل Android Automotive از سطح API برنامه Car پشتیبانی می شود
fetchModel ساخت، مدل، سال android.car.permission.CAR_INFO 3
fetchEnergyProfile انواع کانکتور EV، انواع سوخت com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

این داده‌ها فقط در برخی از خودروهای دارای سیستم عامل Android Automotive دارای API 30 یا بالاتر موجود است

ابعاد بیرونی N/A 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 ایجاد و ثبت کنید:

کاتلین
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)
جاوا
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 به ​​شما امکان دسترسی به شتاب سنج، ژیروسکوپ، قطب نما و داده های موقعیت مکانی خودرو را می دهد. در دسترس بودن این مقادیر ممکن است به OEM بستگی داشته باشد. فرمت داده‌های شتاب‌سنج، ژیروسکوپ و قطب‌نما همان است که از SensorManager API دریافت می‌کنید. به عنوان مثال، برای بررسی عنوان خودرو:

کاتلین
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)
جاوا
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 Automobile ، به بخش Emulate Hardware State از راهنمای Emulator OS Android Automobile Os مراجعه کنید.

چرخه های حیات Carappservice ، Session و Screen

کلاس های Session و Screen رابط LifecycleOwner را پیاده سازی می کنند. از آنجا که کاربر با برنامه در تعامل است ، همانطور که در نمودارهای زیر توضیح داده شده است ، از تماس های چرخه عمر Session و Screen اشیاء استفاده می شود.

چرخه های حیات یک سرویس دهنده و یک جلسه
شکل 1 . چرخه حیات Session .

برای جزئیات کامل ، به مستندات روش Session.getLifecycle مراجعه کنید.

چرخه عمر یک صفحه نمایش
شکل 2 . چرخه عمر Screen .

برای جزئیات کامل ، به مستندات روش Screen.getLifecycle مراجعه کنید.

ضبط از میکروفون ماشین

با استفاده از CarAppService برنامه و API CarAudioRecord ، می توانید برنامه خود را به میکروفون ماشین کاربر دسترسی دهید. کاربران برای دسترسی به میکروفون خودرو باید به برنامه شما اجازه دهند. برنامه شما می تواند ورودی کاربر را در برنامه شما ضبط و پردازش کند.

اجازه ضبط

قبل از ضبط هرگونه صدا ، ابتدا باید اجازه ضبط در AndroidManifest.xml خود را اعلام کنید و درخواست کنید که کاربر آن را اعطا کند.

<manifest ...>
   ...
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   ...
</manifest>

شما باید در زمان اجرا مجوز ضبط را درخواست کنید. برای جزئیات بیشتر در مورد نحوه درخواست مجوز در برنامه ماشین خود ، به بخش مجوزهای درخواست مراجعه کنید.

ضبط صدا

بعد از اینکه کاربر اجازه ضبط را می دهد ، می توانید صدا را ضبط کرده و ضبط را پردازش کنید.

کاتلین
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()
 
جاوا
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();
 
تمرکز صوتی

هنگام ضبط از میکروفون خودرو ، ابتدا فوکوس صوتی را به دست می آورید تا اطمینان حاصل شود که هر رسانه در حال انجام است. اگر تمرکز صوتی را از دست دادید ، ضبط را متوقف کنید.

در اینجا نمونه ای از نحوه دستیابی به تمرکز صوتی آورده شده است:

کاتلین
 
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
جاوا
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 صحیح ایجاد و بازگردانده شده است.

برای نمونه های استفاده به نمونه ها مراجعه کنید.

گزارش یک اندرویدی برای شماره کتابخانه برنامه خودروها

اگر مشکلی با کتابخانه پیدا کردید ، آن را با استفاده از ردیاب شماره Google گزارش دهید. حتماً تمام اطلاعات درخواستی را در الگوی شماره پر کنید.

یک شماره جدید ایجاد کنید

قبل از تشکیل مسئله جدید ، لطفاً بررسی کنید که آیا در یادداشت های انتشار کتابخانه ذکر شده است یا در لیست شماره ها گزارش شده است. با کلیک بر روی ستاره برای مسئله در ردیاب می توانید مشترک شوید و به موضوعات رای دهید. برای اطلاعات بیشتر ، به عضویت در یک موضوع مراجعه کنید.