ספריית האפליקציות של 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
: אפליקציה שמאפשרת למשתמשים לבצע פעולות רלוונטיות במכשירים מחוברים מתוך הרכב. איך יוצרים אפליקציות ל-Internet of Things לרכביםandroidx.car.app.category.WEATHER
: אפליקציה שמאפשרת למשתמשים לראות מידע רלוונטי על מזג האוויר שקשור למיקום הנוכחי שלהם או למסלול שלהם. איך יוצרים אפליקציות מזג אוויר לרכב
במאמר איכות אפליקציות 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()
.
מצהירים על רמת ה-API המינימלית של אפליקציית הרכב שנתמכת באפליקציה בקובץ AndroidManifest.xml
:
<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 |
ניווט, נקודות עניין, מזג האוויר |
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
של פונקציות ה-call back onSurfaceAvailable()
ו-onSurfaceDestroyed()
.
Kotlin
carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)
Java
carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);
הסבר על האזור הגלוי של המשטח
המארח יכול לצייר רכיבי ממשק משתמש של התבניות מעל המפה. המארח מודיע על האזור של המשטח שבטוח שהוא ללא חסימות וחשוף במלואו למשתמש, על ידי קריאה לשיטה 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 |
הוספת סרגל פעולות למפה
התבניות האלה יכולות לכלול סרגל פעולות של מפה לפעולות שקשורות למפה, כמו הגדלה והקטנה של התצוגה, מרכוז מחדש, הצגת מצפן ופעולות אחרות שתרצו להציג. אפשר להוסיף לסרגל הפעולות במפה עד ארבעה לחצנים עם סמלים בלבד, שאפשר לרענן בלי להשפיע על עומק המשימה. הוא מוסתר במצב חוסר פעילות ומופיע מחדש במצב פעילות.
כדי לקבל קריאות חזרה של אינטראקטיביות במפה, חובה להוסיף לחצן 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)
אפשר להפעיל את השיטה CarContext.startCarApp
כדי לבצע אחת מהפעולות הבאות:
- פותחים את החייגן כדי להתקשר.
- מתחילים מסלול מפורט למיקום מסוים באמצעות אפליקציית הניווט שמוגדרת כברירת מחדל ברכב.
- איך מתחילים אפליקציה משלכם באמצעות כוונה (intent).
בדוגמה הבאה מוסבר איך ליצור התראה עם פעולה שפותחת את האפליקציה עם מסך שבו מוצגים פרטי ההזמנה לחניה.
מרחיבים את מופע ההתראה באמצעות כוונה לתוכן שמכילה 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 מהסיבות הבאות:
- חוויית משתמש משופרת וניהול קל יותר של החשבונות: המשתמשים יכולים לנהל בקלות את כל החשבונות שלהם מתפריט החשבונות בהגדרות המערכת, כולל כניסה לחשבון ויציאה ממנו.
- חוויות 'אורח': מאחר שרכבים הם מכשירים משותפים, יצרני ציוד מקורי יכולים להפעיל חוויות 'אורח' ברכב, שבהן אי אפשר להוסיף חשבונות.
הוספת וריאנטים של מחרוזות טקסט
בגדלים שונים של מסכים ברכב עשויות להופיע כמויות שונות של טקסט. בגרסה 2 ואילך של Car App API, אפשר לציין כמה וריאנטים של מחרוזת טקסט כדי להתאים אותה בצורה הטובה ביותר למסך. כדי לראות איפה אפשר להשתמש באפשרויות טקסט, מחפשים תבניות ורכיבים שמקבלים את הערך 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
מעניקה גישה לנתוני המיקום, למד התאוצה, לג'ירוסקופ ולמצפן של הרכב. זמינות הערכים האלה עשויה להשתנות בהתאם ליצרן הציוד המקורי. הפורמט של הנתונים ממד התאוצה, מהג'ירוסקופ וממצפן זהה לפורמט של הנתונים שמתקבלים מ-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
פרטים מלאים זמינים במסמכי התיעוד של השיטה 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. חשוב למלא את כל המידע הנדרש בתבנית הדיווח על הבעיה.
לפני שמדווחים על בעיה חדשה, כדאי לבדוק אם היא מופיעה בהערות למהדורה של הספרייה או ברשימה של הבעיות. כדי להירשם לבעיות ולצבוע עליהן, לוחצים על הכוכב של הבעיה במעקב. מידע נוסף זמין במאמר הרשמה לבעיה.