ספריית האפליקציות של Android למכוניות מאפשרת לכם להביא לרכב את אפליקציות הניווט, את נקודת העניין (POI) ואת האינטרנט של הדברים (IOT). כדי לעשות זאת, המערכת מספקת קבוצה של תבניות שנועדו לעמוד בתקנים של הסחת דעת של הנהגים, ומתמקדת בפרטים כמו מגוון הגורמים של מסך הרכב ומודל הקלט.
המדריך הזה מספק סקירה כללית על התכונות והמושגים העיקריים של הספרייה, ומראה לכם את תהליך ההגדרה של אפליקציה בסיסית.
לפני שמתחילים
- כדאי לעיין בדפים של עיצוב לנהיגה שעוסקים בספריית האפליקציות לרכב.
- סקירות כלליות של הקטגוריות אפליקציות ניווט ואפליקציות אחרות הקשורות לנהיגה
- סקירה כללית בנושא בניית אפליקציות באמצעות תבניות
- אבני בניין שכוללות תבניות ורכיבי תבנית
- תהליכים לדוגמה שממחישים דפוסים נפוצים של חוויית משתמש
- דרישות לגבי אפליקציות לפי תבנית
- כדאי לעיין במונחים והמושגים המרכזיים בקטע הבא.
- כדאי להכיר את ממשק המשתמש של מערכת Android Auto ואת העיצוב של Android Automotive OS.
- כדאי לעיין בנתוני הגרסה.
- כדאי לעיין בטעימות.
מונחים ומושגים מרכזיים
- מודלים ותבניות
- ממשק המשתמש מיוצג על ידי גרף של אובייקטים של מודל שאפשר לארגן יחד בדרכים שונות, בהתאם לשימוש בתבנית שאליה הם שייכים. תבניות הן קבוצת משנה של המודלים שיכולים לשמש כשורש בתרשים. מודלים כוללים את המידע שיוצג למשתמש בצורה של טקסט ותמונות, וגם מאפיינים כדי להגדיר היבטים של המראה החזותי של המידע הזה — לדוגמה, צבעי טקסט או גדלים של תמונות. המארח ממיר את המודלים לתצוגות שנועדו לעמוד בסטנדרטים של הסחות דעת של הנהג, ומטפל בפרטים כמו מגוון הגורמים של המסך ברכב ותבניות הקלט.
- מארח
- המארח הוא רכיב הקצה העורפי שמטמיע את הפונקציונליות שמציעים ממשקי ה-API של הספרייה, כדי שהאפליקציה תוכל לפעול ברכב. המארח אחראי על גילוי האפליקציה וניהול מחזור החיים שלה, על המרת המודלים לתצוגות ועל שליחת התראות לאפליקציה על אינטראקציות של משתמשים. במכשירים ניידים, המארח הזה מיושם על ידי Android Auto. ב-Android Automotive OS, המארח הזה מותקן כאפליקציית מערכת.
- הגבלות על תבניות
- תבניות שונות אוכפות הגבלות על התוכן של המודלים שלהן. לדוגמה, בתבניות של רשימות יש מגבלות על מספר הפריטים שאפשר להציג למשתמש. יש גם הגבלות על האופן שבו אפשר לקשר תבניות כדי ליצור את תהליך העבודה של המשימה. לדוגמה, האפליקציה יכולה לדחוף לסטאק המסכים עד חמש תבניות. פרטים נוספים זמינים במאמר הגבלות על תבניות.
Screen
Screen
היא מחלקה שמסופקת על ידי הספרייה שאפליקציות מטמיעות כדי לנהל את ממשק המשתמש שמוצג למשתמש. ל-Screen
יש מחזור חיים והוא מספק את המנגנון שבו האפליקציה תשלח את התבנית כך שתוצג במסך. אפשר גם לדחוף ולשלוף מכונותScreen
אל מקבץScreen
וממנו, כדי לוודא שהן עומדות בהגבלות על תהליך היצירה של התבניות.CarAppService
CarAppService
היא כיתה מופשטת מסוגService
שצריך להטמיע ולייצא מהאפליקציה כדי שהמארח יוכל לזהות ולנהל אותה. באחריותCarAppService
של האפליקציה שלכם לאמת שהחיבור של המארח יכול להיות מהימן באמצעותcreateHostValidator
, ולאחר מכן לספק מכונות שלSession
לכל חיבור באמצעותonCreateSession
.Session
Session
היא מחלקה מופשטת שהאפליקציה צריכה להטמיע ולהחזיר באמצעותCarAppService.onCreateSession
. היא משמשת כנקודת הכניסה להצגת מידע במסך הרכב. יש לו מחזור חיים שמציין את המצב הנוכחי של האפליקציה במסך הרכב, למשל מתי האפליקציה גלויה או מוסתרת.כשמפעילים את
Session
, למשל כשהאפליקציה מופעלת בפעם הראשונה, המארח מבקש להציג את ה-Screen
הראשוני באמצעות המתודהonCreateScreen
.
התקנת ספריית האפליקציות לרכב
הוראות להוספת הספרייה לאפליקציה מפורטות בדף הגרסה של ספריית Jetpack.
הגדרת קובצי המניפסט של האפליקציה
לפני שתיצרו את אפליקציית הרכב, עליכם להגדיר את קובצי המניפסט של האפליקציה באופן הבא.
הצהרה על CarAppService
המארח מתחבר לאפליקציה דרך ההטמעה של CarAppService
. כדי לאפשר למארח לגלות את האפליקציה שלכם ולהתחבר אליה, צריך להצהיר על השירות הזה במניפסט.
צריך גם להצהיר על הקטגוריה של האפליקציה ברכיב <category>
של מסנן ה-Intent של האפליקציה. הערכים המותרים לאלמנט הזה מפורטים ברשימת הקטגוריות הנתמכות של האפליקציות.
קטע הקוד הבא מראה איך להצהיר על שירות של אפליקציה לרכב לאפליקציה של נקודת עניין במניפסט:
<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>
קטגוריות של אפליקציות נתמכות
להצהיר על קטגוריית האפליקציה, צריך להוסיף אחד או יותר מערכי הקטגוריות הבאים במסנן Intent כשמצהירים על CarAppService
כפי שמתואר בקטע הקודם:
androidx.car.app.category.NAVIGATION
: אפליקציה שמספקת מסלולי ניווט מפורטים. למידע נוסף על הקטגוריה הזו, אפשר לעיין במאמר פיתוח אפליקציות ניווט לכלי רכב.androidx.car.app.category.POI
: אפליקציה שמספקת פונקציונליות רלוונטית למציאת נקודות עניין, כמו מקומות חניה, תחנות טעינה ותחנות דלק. למידע נוסף על הקטגוריה הזו, אפשר לעיין במאמר יצירת אפליקציות של נקודות עניין לכלי רכב.androidx.car.app.category.IOT
: אפליקציה שמאפשרת למשתמשים לבצע פעולות רלוונטיות במכשירים מחוברים מתוך הרכב. אפשר להיעזר במאמר איך מפתחים אפליקציות לאינטרנט בשביל מכוניות כדי לקרוא מסמכים נוספים על הקטגוריה הזו.
במאמר איכות אפליקציות 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>
רמת ה-API של האפליקציה לרכב
ספריית האפליקציות של הרכב מגדירה רמות API משלה, כדי שתוכלו לדעת אילו תכונות ספרייה נתמכות על ידי מארח התבניות ברכב.
כדי לאחזר את רמת ה-API הגבוהה ביותר של אפליקציה לרכב שנתמכת על ידי מארח, משתמשים ב-method getCarAppApiLevel()
.
בקובץ AndroidManifest.xml
, צריך להצהיר על רמת ה-API המינימלית של אפליקציית Car באפליקציה שלך:
<manifest ...>
<application ...>
<meta-data
android:name="androidx.car.app.minCarApiLevel"
android:value="1"/>
</application>
</manifest>
במסמכי העזרה של ההערה RequiresCarApi
מוסבר איך לשמור על תאימות לאחור ולהצהיר על רמת ה-API המינימלית הנדרשת לשימוש בתכונה. כדי לבדוק איזה רמת API נדרשת כדי להשתמש בתכונה מסוימת של ספריית האפליקציות לרכב, אפשר לעיין במסמכי העזרה של 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
מציע גם פונקציונליות נוספת, כמו אפשרות לטעון משאבים גרפיים באמצעות ההגדרות במסך הרכב, הפעלת אפליקציה ברכב באמצעות כוונות (intents) ויצירת אות לכך שהמפה באפליקציה צריכה להופיע בעיצוב כהה.
הטמעת ניווט במסך
לרוב, באפליקציות יש כמה מסכים שונים, שיכול להיות שבכל אחד מהם נעשה שימוש בתבניות שונות. המשתמש יכול לנווט בין המסכים האלה תוך כדי אינטראקציה עם הממשק שמוצג במסך.
המחלקה 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
על ידי קריאה ל-method Screen.invalidate
.
לאחר מכן, המארח קורא חזרה לשיטה 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
של הקריאות החוזרות (callback) של onSurfaceAvailable()
ו-onSurfaceDestroyed()
.
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
הסבר על האזור הגלוי של המשטח
המארח יכול לשרטט רכיבים של ממשק המשתמש עבור התבניות מעל המפה. המארח מודיע על האזור של המשטח שבטוח שהוא ללא חסימות וחשוף במלואו למשתמש, על ידי קריאה ל-method SurfaceCallback.onVisibleAreaChanged
. בנוסף, כדי למזער את מספר השינויים, המארח קורא לשיטה SurfaceCallback.onStableAreaChanged
עם המלבן הקטן ביותר, שהוא תמיד גלוי על סמך התבנית הנוכחית.
לדוגמה, כשאפליקציית ניווט משתמשת בNavigationTemplate
עם רצועת פעולות בחלק העליון, רצועת הפעולות יכולה להסתתר אם המשתמש לא ביצע פעולה כלשהי במסך במשך זמן מה, כדי לפנות מקום למפה. במקרה כזה, מתבצעת קריאה חוזרת (callback) ל-onStableAreaChanged
ול-onVisibleAreaChanged
עם אותו מלבן. כשרצועת הפעולות מוסתרת, רק onVisibleAreaChanged
נקרא עם האזור הגדול יותר. אם המשתמש יוצר אינטראקציה עם המסך, שוב רק onVisibleAreaChanged
ייכלל בקריאה עם המלבן הראשון.
תמיכה בעיצוב כהה
אפליקציות צריכות לצייר מחדש את המפה שלהן במכונה Surface
עם הצבעים הכהים המתאימים, כשהמארח קובע שהנסיבות מצדיקות זאת, כפי שמתואר במאמר איכות האפליקציות של Android למכוניות.
כדי להחליט אם לצייר מפה כהה, אפשר להשתמש ב-method CarContext.isDarkMode
. בכל פעם שסטטוס העיצוב הכהה משתנה, תקבלו שיחה למספר Session.onCarConfigurationChanged
.
מאפשרים למשתמשים לבצע פעולות במפה
כשמשתמשים בתבניות הבאות, אפשר להוסיף תמיכה במשתמשים כדי לקיים אינטראקציה עם המפות שציירתם, למשל לאפשר להם לראות חלקים שונים של המפה על ידי שינוי מרחק התצוגה והזזה.
תבנית | תמיכה באינטראקטיביות החל מרמת ה-API של אפליקציית הרכב |
---|---|
NavigationTemplate |
2 |
PlaceListNavigationTemplate (הווצא משימוש) |
4 |
RoutePreviewNavigationTemplate (הווצא משימוש) |
4 |
MapTemplate (הווצא משימוש) |
5 (introduction of template) |
MapWithContentTemplate |
7 (introduction of template) |
הטמעת קריאות חזרה (callbacks) של אינטראקטיביות
לממשק SurfaceCallback
יש כמה שיטות קריאה חוזרת (callback) שאפשר להטמיע כדי להוסיף אינטראקטיביות למפות שנוצרו באמצעות התבניות בקטע הקודם:
אינטראקציה | השיטה SurfaceCallback |
נתמכת החל מרמת API של אפליקציה לרכב |
---|---|---|
הקשה | onClick |
5 |
אפשר לצבוט כדי לשנות את מרחק התצוגה | onScale |
2 |
גרירה בנגיעה אחת | onScroll |
2 |
החלקה בנגיעה אחת | onFling |
2 |
הקשה כפולה | onScale (עם גורם קנה מידה שנקבע על ידי מארח התבנית) |
2 |
דחיפה סיבובית במצב הזזה | onScroll (עם גורם מרחק שנקבע על ידי מארח התבנית) |
2 |
הוספת סרגל פעולות למפה
התבניות האלה יכולות לכלול פס פעולות של מפה לפעולות שקשורות למפה, כמו הגדלה והקטנה של התצוגה, מרכוז מחדש, הצגת מצפן ופעולות אחרות שתרצו להציג. אפשר להוסיף לסרגל הפעולות במפה עד ארבעה לחצנים עם סמלים בלבד, שאפשר לרענן בלי להשפיע על עומק המשימה. הוא מוסתר במצב חוסר פעילות ומופיע מחדש במצב פעילות.
כדי לקבל קריאות חוזרות (callback) של אינטראקטיביות במפה, צריך להוסיף את הלחצן Action.PAN
בשורת הפעולות במפה. כשהמשתמש מקשיב על לחצן ה-Pan, המארח עובר למצב Pan, כפי שמתואר בקטע הבא.
אם האפליקציה שלכם לא כוללת את הלחצן Action.PAN
בסרגל הפעולות של המפה, היא לא תקבל קלט מהמשתמשים מהשיטות SurfaceCallback
והמארח ייצא מכל מצב החלקה שהופעל בעבר.
במסך מגע, לחצן התנועה לא מוצג.
הסבר על מצב הזזה
במצב 'הזזה', מארח התבנית מתרגם את הקלט של המשתמש ממכשירי קלט ללא מגע, כמו בקרי רוטורים ומשטחי מגע, לשיטות SurfaceCallback
המתאימות. מגיבים לפעולה של המשתמש כדי להיכנס או לצאת ממצב ה-pan באמצעות השיטה 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); }
לפרטים נוספים על הפעלת אפליקציות, כולל הפורמט של ה-Intent ACTION_NAVIGATE
, עיינו בקטע התנעת רכב עם Intent.
חלק מהפעולות, כמו פעולות שדורשות להפנות את המשתמש להמשיך את האינטראקציה בנייד, מותרות רק כשהרכב חונה.
אפשר להשתמש ב-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();
ההתראות יכולות להשפיע על החלקים הבאים בממשק המשתמש:
- יכול להיות שתוצג למשתמש התראה מראש (HUN).
- יכול להיות שתתווסף רשומה במרכז ההתראות, עם תג שאפשר לראות ברכבת.
- באפליקציות ניווט, יכול להיות שההתראה תוצג בווידג'ט הרכב כפי שמתואר בהתראות מסלול מפורט.
אתם יכולים להגדיר את ההתראות של האפליקציה כך שישפיעו על כל אחד מרכיבי ממשק המשתמש האלה באמצעות העדיפות של ההתראה, כפי שמתואר במסמכי העזרה של 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. כדי לבקש הרשאה, אפשר להשתמש ב-method 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>
הפעלת אפליקציה לרכב באמצעות כוונה (intent)
אפשר לשלוח קריאה ל-method CarContext.startCarApp
כדי לבצע אחת מהפעולות הבאות:
- פותחים את החייגן כדי להתקשר.
- מתחילים מסלול מפורט למיקום מסוים באמצעות אפליקציית הניווט שמוגדרת כברירת מחדל ברכב.
- להתחיל אפליקציה משלכם עם כוונה.
בדוגמה הבאה אפשר לראות איך ליצור התראה עם פעולה שפותחת את האפליקציה במסך שמציג את הפרטים של הזמנת חניה.
מרחיבים את מופע ההתראה באמצעות כוונה לתוכן שמכילה PendingIntent
שמקיפה כוונה מפורשת לפעולה של האפליקציה:
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
עם כוונה שכוללת את ה-URI של הנתונים:
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())); } } }
בקטע הצגת התראות מוסבר איך לטפל בהתראות באפליקציה לרכב.
הגבלות על תבניות
המארח מגביל את מספר התבניות שמוצגות למשימה מסוימת לחמש תבניות לכל היותר, והתבנית האחרונה חייבת להיות מאחד מהסוגים הבאים:
חשוב לזכור שהמגבלה הזו חלה על מספר התבניות ולא על מספר המכונות של Screen
בסטאק. לדוגמה, אם אפליקציה שולחת שני תבניות במסך א' ואז דוחפת את המסך ב', היא יכולה לשלוח עכשיו עוד שלוש תבניות. לחלופין, אם כל מסך בנוי לשליחה של תבנית יחידה, האפליקציה יכולה לדחוף חמישה מופעים של מסך למקבץ ScreenManager
.
יש מקרים מיוחדים שבהם ההגבלות האלה לא חלות: רענון תבניות ופעולות של חזרה אחורה ואיפוס.
רענון התבניות
עדכוני תוכן מסוימים לא נספרים במסגרת המגבלה על התבניות. באופן כללי, אם אפליקציה דוחפת תבנית חדשה מאותו סוג שמכילה את אותו תוכן ראשי כמו התבנית הקודמת, התבנית החדשה לא נספרת במסגרת המכסה. לדוגמה, עדכון מצב החלפת המצב של שורה ב-ListTemplate
לא נספר בהשוואה למכסה. במסמכי העזרה של התבניות השונות מוסבר מהם סוגי העדכונים של התוכן שאפשר להתייחס אליהם כרענון.
פעולות אחורה
כדי להפעיל תהליכי משנה בתוך משימה, המארח מזהה מתי אפליקציה מוציאה Screen
מהמקבץ ScreenManager
ומעדכן את המכסה שנותרה על סמך מספר התבניות שהאפליקציה חוזרת אליהן אחורה.
לדוגמה, אם האפליקציה שולחת שתי תבניות במסך א', ואז מעבירה את המסך ל-B ושולחת עוד שתי תבניות, לאפליקציה תישאר מכסה אחת. אם האפליקציה תופיע שוב במסך א', המארח יחזיר את המכסה ל-3, כי האפליקציה חזרה אחורה בשני תבניות.
חשוב לזכור: כשחוזרים למסך, האפליקציה צריכה לשלוח תבנית מאותו סוג כמו זו שנשלחה מהמסך הזה בפעם האחרונה. שליחת תבנית מסוג אחר תגרום לשגיאה. עם זאת, כל עוד הסוג לא משתנה במהלך פעולה קודמת, האפליקציה יכולה לשנות את התוכן של התבנית באופן חופשי בלי להשפיע על המכסה.
פעולות איפוס
לתבניות מסוימות יש סמנטיקה מיוחדת שמציינת את סיום המשימה. לדוגמה, NavigationTemplate
הוא תצוגה שצפויה להישאר במסך ולהתעדכן בהוראות מפורטות חדשות למשתמש. כשהיא מגיעה לאחת מהתבניות האלה, המארח מאפס את המכסה של התבנית, ומתייחס אל התבנית הזו כאילו היא השלב הראשון של משימה חדשה. כך האפליקציה יכולה להתחיל משימה חדשה.
אפשר לעיין במסמכי התיעוד של תבניות ספציפיות כדי לבדוק אילו מהן גורמות לאיפוס במארח.
אם המארח מקבל כוונה להפעיל את האפליקציה מפעולת התראה או ממרכז האפליקציות, גם המכסה מתאפסת. המנגנון הזה מאפשר לאפליקציה להתחיל תהליך משימות חדש מהתראות, גם אם האפליקציה כבר מקושרת ונמצאת בחזית.
בקטע הצגת התראות מוסבר בהרחבה איך להציג את ההתראות מהאפליקציה במסך הרכב. בקטע הפעלת אפליקציה לרכב באמצעות כוונה מוסבר איך מפעילים את האפליקציה באמצעות פעולה בהתראה.
Connection API
כדי לקבוע אם האפליקציה פועלת ב-Android Auto או ב-Android Automotive OS, אפשר להשתמש ב-CarConnection
API כדי לאחזר את פרטי החיבור בזמן הריצה.
לדוגמה, ב-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
עם Car App API ברמה 2 ואילך כדי לטפל בכניסה לאפליקציה במסך הרכב.
כדי ליצור SignInTemplate
, מגדירים SignInMethod
. בשלב הזה, בספריית האפליקציות לרכב יש תמיכה בשיטות הכניסה הבאות:
InputSignInMethod
כדי להיכנס באמצעות שם משתמש וסיסמה.PinSignInMethod
להתחברות באמצעות מספר PIN, שבה המשתמש מקשר את החשבון שלו מהטלפון באמצעות מספר PIN שמוצג במכשיר הראשי.ProviderSignInMethod
כניסה באמצעות ספק, כמו כניסה באמצעות חשבון Google ו-One Tap.QRCodeSignInMethod
כניסה באמצעות קוד QR, שבה המשתמש סורק קוד QR כדי להשלים את הכניסה בטלפון. התכונה הזו זמינה ב-Car API ברמה 4 ואילך.
לדוגמה, כדי להטמיע תבנית שאוספת את הסיסמה של המשתמש, מתחילים ביצירת 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 OS עם אימות חייבות להשתמש ב-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 text styling with Spans מוסבר איך עובדת הוספת סגנון לטקסט באמצעות Spans.
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();
ממשקי API לחומרת רכב
החל מרמת API 3 של Car App API, בספריית האפליקציות לרכב יש ממשקי API שאפשר להשתמש בהם כדי לגשת לחיישנים ולמאפיינים של הרכב.
הדרישות
כדי להשתמש ב-API עם Android Auto, קודם צריך להוסיף יחסי תלות ל-androidx.car.app:app-projected
לקובץ build.gradle
של המודול של Android Auto. ב-Android Automotive OS, מוסיפים יחסי תלות ב-androidx.car.app:app-automotive
לקובץ build.gradle
של המודול של Android Automotive OS.
בנוסף, בקובץ AndroidManifest.xml
צריך להצהיר על ההרשאות הרלוונטיות שנדרשות כדי לבקש את נתוני הרכב שבהם אתם רוצים להשתמש. חשוב לזכור שגם המשתמש צריך להעניק לכם את ההרשאות האלה. אתם יכולים להשתמש באותו קוד גם ב-Android Auto וגם ב-Android Automotive OS, במקום ליצור תהליכים שתלויים בפלטפורמה. עם זאת, ההרשאות הנדרשות שונות.
CarInfo
בטבלה הבאה מתוארים המאפיינים שמוצגים על ידי ממשקי ה-API של CarInfo
וההרשאות שצריך לבקש כדי להשתמש בהם:
שיטות | מאפיינים | הרשאות של Android Auto | הרשאות של Android Automotive OS | נתמכת החל מרמת 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 OS שמריצים API מגרסה 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 OS לאפליקציות שמותקנות מחנות 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
מעניקה גישה לנתוני המיקום, למד התאוצה, לג'ירוסקופ ולמצפן של הרכב. זמינות הערכים האלה עשויה להשתנות בהתאם ליצרן הציוד המקורי (OEM). הפורמט של הנתונים ממד התאוצה, מהג'ירוסקופ וממצפן זהה לפורמט של הנתונים שמתקבלים מ-SensorManager
API. לדוגמה, כדי לבדוק את כיוון הרכב:
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 OS, תוכלו לעיין בקטע אמולציה של מצב החומרה במדריך לאמולטור Android Automotive OS.
מחזור החיים של CarAppService, Session ו-Screen
המחלקות Session
ו-Screen
מטמיעות את הממשק LifecycleOwner
. כשהמשתמש מבצע פעולות באפליקציה, מתבצעת קריאה חוזרת (callback) למחזור החיים של האובייקטים Session
ו-Screen
, כפי שמתואר בתרשים הבא.
מחזור החיים של CarAppService ושל Session
לקבלת פרטים מלאים, עיינו במסמכי העזרה של ה-method Session.getLifecycle
.
מחזור החיים של מסך
פרטים מלאים זמינים במסמכי העזרה של השיטה Screen.getLifecycle
.
הקלטה מהמיקרופון ברכב
באמצעות CarAppService
של האפליקציה ו-API של 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 למכוניות יש שיעורי עזר שבהם אפשר להשתמש כדי לאמת את התנהגות האפליקציה בסביבת בדיקה.
לדוגמה, הפונקציה SessionController
מאפשרת לדמות חיבור למארח ולוודא שנוצרו והוחזרו הערכים הנכונים של Screen
ושל Template
.
בדוגמאות מפורטות דוגמאות לשימוש.
דיווח על בעיה בספריית האפליקציות של Android למכוניות
אם נתקלתם בבעיה בספרייה, תוכלו לדווח עליה באמצעות מעקב הבעיות של Google. חשוב למלא את כל המידע הנדרש בתבנית הדיווח על הבעיה.
לפני שמדווחים על בעיה חדשה, כדאי לבדוק אם היא מופיעה בהערות למהדורה של הספרייה או בדיווח ברשימת הבעיות. אתם יכולים להירשם ולהצביע על בעיות בלחיצה על הכוכב של בעיה בכלי המעקב. מידע נוסף זמין במאמר הרשמה לבעיה.