Instrument Cluster API

אפשר להשתמש ב-Instrument Cluster API (ממשק API ל-Android) כדי להציג אפליקציות ניווט, כולל מפות Google, במסך משני ברכב, למשל מאחורי ההגה בלוח המחוונים. בדף הזה נסביר איך ליצור שירות לניהול המסך המשני, ואיך לשלב את השירות עם CarService כדי שאפליקציות ניווט יוכלו להציג ממשק משתמש.

טרמינולוגיה

בדף הזה נעשה שימוש במונחים הבאים.

CarInstrumentClusterManager
מכונה של CarManager שמאפשרת לאפליקציות חיצוניות להפעיל פעילות באשכול הכלים ולקבל קריאות חזרה כשאשכול הכלים מוכן להציג פעילויות.
CarManager
המחלקה הבסיסית של כל המנהלים שמשמשים אפליקציות חיצוניות כדי ליצור אינטראקציה עם שירותים ספציפיים לרכב שמוטמעים על ידי CarService.
CarService
שירות של פלטפורמת Android שמאפשר תקשורת בין אפליקציות חיצוניות (כולל מפות Google) לבין תכונות ספציפיות לרכב, כמו גישה למרכז המכשירים.
יעד
היעד הסופי שאליו הרכב ינווט.
זמן ההגעה המשוער (ETA)
זמן ההגעה המשוער ליעד.
יחידה ראשית (HU)
יחידה מחשוב ראשית שמוטמעת ברכב. ה-HU מפעיל את כל הקוד של Android ומחובר למסך המרכזי ברכב.
אשכול הכלים
מסך משני שממוקם מאחורי ההגה ובין מכשירי הרכב. זה יכול להיות יחידה מחשובית עצמאית שמחוברת למסך הראשי דרך הרשת הפנימית של הרכב (CAN bus) או מסך משני שמחובר למסך הראשי.
InstrumentClusterRenderingService
הקלאס הבסיסי של השירות שמשמש לממשק עם המסך של מרכז המכשירים. יצרני ציוד מקורי צריכים לספק תוסף של המחלקה הזו שמקיים אינטראקציה עם החומרה הספציפית ליצרן הציוד המקורי.
אפליקציית KitchenSink
אפליקציית בדיקה שכלולה ב-Android Automotive.
מסלול
נתיב ספציפי שבו כלי רכב מנווט כדי להגיע ליעד.
שירות singleton
שירות Android עם המאפיין android:singleUser. בכל זמן נתון, רק מופע אחד של השירות פועל במערכת Android.

דרישות מוקדמות

לפני שממשיכים, חשוב לוודא שיש לכם את הפריטים הבאים:

  • סביבת פיתוח ל-Android במאמר דרישות ה-build מוסבר איך מגדירים את סביבת הפיתוח של Android.
  • מורידים את קוד המקור של Android. מורידים את הגרסה האחרונה של קוד המקור של Android מההסתעפות pi-car-release (או מאוחר יותר) בכתובת https://android.googlesource.com.
  • יחידה ראשית (HU). מכשיר Android שיכול להריץ את Android 9 (או גרסה מתקדמת יותר). למכשיר הזה צריך להיות מסך משלו, והוא צריך לאפשר לכם להריץ בו גרסאות build חדשות של Android.
  • Instrument Cluster הוא אחד מהבאים:
    • מסך משני פיזי שמחובר למסך הראשי. אם החומרה והליבה של המכשיר תומכים בניהול של כמה מסכים.
    • יחידה עצמאית. כל יחידה מחשוב שמחוברת ל-HU דרך חיבור רשת, עם יכולת לקבל ולציג שידור וידאו במסך משלה.
    • תצוגה ממולאלת במהלך הפיתוח, אפשר להשתמש באחת מסביבות ההדמיה הבאות:
      • הדמיה של מסכים משניים כדי להפעיל תצוגה משנית מדומה בכל הפצות Android של AOSP, עוברים להגדרות של אפשרויות למפתחים באפליקציית המערכת הגדרות ובוחרים באפשרות הדמיה של תצוגות משניות. ההגדרה הזו זהה לחיבור של תצוגה משנית פיזית, עם המגבלה שהתצוגה הזו חופפת לתצוגה הראשית.
      • אשכול כלים בגרסת אמולטור במהדורת Android Emulator שכלולה ב-AAOS יש אפשרות להציג אשכול מכשירים באמצעות ClusterRenderingService.

ארכיטקטורת השילוב

רכיבי השילוב

כל שילוב של Instrument Cluster API מורכב משלושת הרכיבים הבאים:

  • CarService
  • אפליקציות ניווט
  • שירות אשכול הכלים של יצרן ציוד מקורי

רכיבי השילוב

CarService

CarService מתווך בין אפליקציות הניווט לבין הרכב, ומוודא שרק אפליקציית ניווט אחת פעילה בכל זמן נתון, ושרק אפליקציות עם ההרשאה android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL יכולות לשלוח נתונים לרכב.

CarService מפעיל את כל השירותים הספציפיים לרכב ומספק גישה לשירותים האלה באמצעות סדרה של מנהלי שירותים. כדי ליצור אינטראקציה עם השירותים, לאפליקציות שפועלות ברכב יש גישה למנהלים האלה.

כדי להטמיע אשכול מכשירים, יצרני ציוד מקורי לכלי רכב צריכים ליצור הטמעה בהתאמה אישית של InstrumentClusterRendererService ולעדכן את ClusterRenderingService.

כשמפעילים עיבוד של אשכול כלים, במהלך תהליך האתחול ה-CarService קורא את המפתח InstrumentClusterRendererService של ClusterRenderingService כדי לאתר הטמעה של InstrumentClusterService. ב-AOSP, הרשומה הזו מפנה לשירות ה-render של ההטמעה לדוגמה של Navigation State API באשכול:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

השירות שמצוין ברשומה הזו מופעל ומקושר ל-CarService. כשאפליקציות ניווט, כמו מפות Google, מבקשות CarInstrumentClusterManager, CarService מספק מנהל שמעדכן את המצב של לוח המחוונים מה-InstrumentClusterRenderingService המקושר. (במקרה הזה, bound מתייחס ל-Android Services).

שירות Instrument Cluster

יצרני ציוד מקורי (OEM) חייבים ליצור חבילת Android ‏(APK) שמכילה קבוצת משנה של ClusterRenderingService.

לכיתה הזו יש שתי מטרות:

  • מספק ממשק בין Android לבין מכשיר הרינדור של אשכול המכשירים (המטרה של הדף הזה).
  • קבלה ורינדור של עדכונים לגבי מצב הניווט, כמו הנחיות מפורטות לניווט.

למטרה הראשונה, הטמעות של InstrumentClusterRendererService על ידי יצרני ציוד מקורי חייבות לאתחל את המסך המשני שמשמש לעיבוד מידע במסכים בתא הנוסעים של הרכב, ולשלוח את המידע הזה ל-CarService באמצעות קריאה לשיטות InstrumentClusterRendererService.setClusterActivityOptions() ו-InstrumentClusterRendererService.setClusterActivityState().

בפונקציה השנייה, שירות Instrument Cluster צריך לספק הטמעה של הממשק ClusterRenderingService שמקבל אירועים של עדכון סטטוס הניווט, שמקודדים כ-eventType ונתוני אירועים שמקודדים בחבילה.

רצף השילוב

בתרשים הבא מודגמת ההטמעה של מצב ניווט שמציג עדכונים:

רצף השילוב

באיור הזה, הצבעים מציינים את הדברים הבאים:

  • צהוב. CarService ו-CarNavigationStatusManager שסופקו על ידי פלטפורמת Android. מידע נוסף זמין במאמרים Car ו-CAR_NAVIGATION_SERVICE.
  • ציאן InstrumentClusterRendererService שהוטמעה על ידי יצרן הציוד המקורי.
  • סגול אפליקציית הניווט ש-Google ומפתחים של צד שלישי מטמיעים.
  • ירוק. CarAppFocusManager. מידע נוסף זמין בקטע שימוש ב-CarAppFocusManager API בהמשך ובמאמר CarAppFocusManager.

תהליך העברת המידע של מצב הניווט מתבצע לפי הסדר הבא:

  1. CarService מאתחלה את InstrumentClusterRenderingService.
  2. במהלך האתחול, InstrumentClusterRenderingService מעדכן את CarService באמצעות:
    1. מאפייני תצוגה של מרכז המכשירים, כמו גבולות לא מוסתרים (פרטים נוספים על גבולות לא מוסתרים מופיעים בהמשך).
    2. אפשרויות הפעילות הנדרשות להפעלת פעילויות במסך של אשכול הכלים. מידע נוסף זמין במאמר ActivityOptions.
  3. אפליקציית ניווט (כמו מפות Google ל-Android Automotive או כל אפליקציית מפות עם ההרשאות הנדרשות):
    1. הצגת CarAppFocusManager באמצעות הכיתה Car מ-car-lib.
    2. לפני תחילת המסלול המפורט, מתבצעות קריאות ל-CarAppFocusManager.requestFocus() כדי להעביר את הערך CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION כפרמטר appType.
  4. CarAppFocusManager מעביר את הבקשה הזו אל CarService. אם ההרשאה תאושר, CarService יבדוק את חבילת אפליקציית הניווט ויאתר פעילות שמסומנת בקטגוריה android.car.cluster.NAVIGATION.
  5. אם הוא נמצא, אפליקציית הניווט משתמשת ב-ActivityOptions שדווח על ידי InstrumentClusterRenderingService כדי להפעיל את הפעילות, ומצרפת את מאפייני התצוגה של אשכול הכלים כפרטים נוספים בכוונה.

שילוב ה-API

ההטמעה של InstrumentClusterRenderingService חייבת:

  • מוסיפים את הערך הבא לקובץ AndroidManifest.xml כדי להגדיר את השירות כשירות יחיד (singleton). הפעולה הזו נחוצה כדי לוודא שעותק יחיד של שירות Instrument Cluster פועל, גם במהלך האתחול והמעבר בין משתמשים:
    android:singleUser="true"
  • לוחצים לחיצה ארוכה על הרשאת המערכת BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. כך מובטח שרק שירות הרינדור של Instrument Cluster שכלול בתמונת מערכת Android יהיה מקושר ל-CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

הטמעת InstrumentClusterRenderingService

כדי ליצור את השירות:

  1. כותבים כיתה שמתרחבת מ-ClusterRenderingService ומוסיפים רשומה תואמת לקובץ AndroidManifest.xml. הכיתה הזו קובעת את התצוגה של אשכול הכלים, ויכולה (אופציונלי) להציג נתוני API של מצב הניווט.
  2. במהלך onCreate(), משתמשים בשירות הזה כדי לאתחל את התקשורת עם חומרת הרינדור. האפשרויות כוללות:
    • קובעים איזה מסך משני ישמש את אשכול המכשירים.
    • יוצרים מסך וירטואלי כדי שהאפליקציה Instrument Cluster תעבד ותשלח את התמונה שעברה עיבוד ליחידת חיצונית (באמצעות פורמט סטרימינג של וידאו, כמו H.264).
  3. כשהתצוגה שצוינה למעלה מוכנה, השירות הזה צריך להפעיל את InstrumentClusterRenderingService#setClusterActivityLaunchOptions() כדי להגדיר את הערך המדויק של ActivityOptions שצריך להשתמש בו כדי להציג פעילות באשכול המכשירים. משתמשים בפרמטרים הבאים:
    • category. ClusterRenderingService.
    • ActivityOptions. מכונה של ActivityOptions שאפשר להשתמש בה כדי להפעיל פעילות באשכול הכלים. לדוגמה, מהטמעה לדוגמה של Instrument Cluster ב-AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. כשאשכול הכלים מוכן להציג פעילויות, השירות הזה צריך להפעיל את InstrumentClusterRenderingService#setClusterActivityState(). משתמשים בפרמטרים הבאים:
    • category ClusterRenderingService.
    • state חבילה שנוצרה באמצעות ClusterRenderingService. חשוב לספק את הנתונים הבאים:
      • visible מציין שהמרכז למדידת מדדים גלוי ומוכן להציג תוכן.
      • unobscuredBounds מלבן שמגדיר את האזור במסך של מרכז המכשירים שבו אפשר להציג תוכן בבטחה. לדוגמה, אזורים שמכוסים במדדים ובשעונים.
  5. משנים את השיטה Service#dump() ומדווחים על נתוני סטטוס שיעזרו בניפוי באגים (מידע נוסף זמין במאמר dumpsys).

דוגמה להטמעה של InstrumentClusterRenderingService

בדוגמה הבאה מפורטת הטמעה של InstrumentClusterRenderingService, שבה נוצר VirtualDisplay כדי להציג את התוכן של Instrument Cluster במסך פיזי מרוחק.

לחלופין, הקוד הזה יכול להעביר את displayId של מסך משני פיזי שמחובר ל-HU, אם ידוע שיש כזה.

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display to be used for instrument
   // cluster
   private final String mUniqueId = UUID.randomUUID().toString();
   // Format of the instrument cluster display
   private static final int DISPLAY_WIDTH = 1280;
   private static final int DISPLAY_HEIGHT = 720;
   private static final int DISPLAY_DPI = 320;
   // Area not covered by instruments
   private static final int DISPLAY_UNOBSCURED_LEFT = 40;
   private static final int DISPLAY_UNOBSCURED_TOP = 0;
   private static final int DISPLAY_UNOBSCURED_RIGHT = 1200;
   private static final int DISPLAY_UNOBSCURED_BOTTOM = 680;
   @Override
   public void onCreate() {
      super.onCreate();
      // Create a virtual display to render instrument cluster activities on
      mDisplayManager = getSystemService(DisplayManager.class);
      VirtualDisplay display = mDisplayManager.createVirtualDisplay(
          mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null,
          0 /* flags */, null, null);
      // Do any additional initialization (e.g.: start a video stream
      // based on this virtual display to present activities on a remote
      // display).
      onDisplayReady(display.getDisplay());
}
private void onDisplayReady(Display display) {
    // Report activity options that should be used to launch activities on
    // the instrument cluster.
    String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION;
    ActionOptions options = ActivityOptions.makeBasic()
        .setLaunchDisplayId(display.getDisplayId());
    setClusterActivityOptions(category, options);
    // Report instrument cluster state.
    Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT,
        DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT,
        DISPLAY_UNOBSCURED_BOTTOM);
    boolean visible = true;
    ClusterActivityState state = ClusterActivityState.create(visible,
       unobscuredBounds);
    setClusterActivityState(category, options);
  }
}

שימוש ב-CarAppFocusManager API

ב-CarAppFocusManager API יש שיטה בשם getAppTypeOwner(), שמאפשרת לשירות האשכולות שנכתב על ידי יצרני ציוד מקורי לדעת לאיזו אפליקציית ניווט יש עדיפות ניווט בכל זמן נתון. יצרני ציוד מקורי יכולים להשתמש בשיטה הקיימת CarAppFocusManager#addFocusListener(), ואז להשתמש ב-getAppTypeOwner() כדי לדעת איזו אפליקציה נמצאת במוקד. בעזרת המידע הזה, יצרני ציוד מקורי יכולים:

  • החלפת הפעילות שמוצגת באשכול לפעילות באשכול שמספקת אפליקציית הניווט שבה מופעל המיקוד.
  • יכולה לזהות אם יש פעילות באשכול באפליקציית הניווט שבה מתמקדים. אם לאפליקציית הניווט שבה מתמקדים אין פעילות באשכול (או אם הפעילות הזו מושבתת), יצרני ציוד מקורי יכולים לשלוח את האות הזה ל-DIM ברכב כדי לדלג על היבט הניווט באשכול לגמרי.

משתמשים ב-CarAppFocusManager כדי להגדיר את מוקד האפליקציה הנוכחי, כמו ניווט פעיל או פקודה קולית, ולהקשיב לו. בדרך כלל רק מופע אחד של אפליקציה כזו פועל באופן פעיל (או ממוקד) במערכת.

משתמשים בשיטה CarAppFocusManager#addFocusListener(..) כדי להאזין לשינויים במיקוד של האפליקציה:

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

...

public void onAppFocusChanged(int appType, boolean active) {
    // Use the CarAppFocusManager#getAppTypeOwner(appType) method call
    // to retrieve a list of active package names
}

משתמשים בשיטה CarAppFocusManager#getAppTypeOwner(..) כדי לאחזר את שמות החבילות של הבעלים הנוכחי של סוג אפליקציה נתון שנמצא במוקד. אם הבעלים הנוכחי משתמש בתכונה android:sharedUserId, יכול להיות שהשיטה הזו תחזיר יותר משם חבילה אחד.

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner(
              CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) {
        // No Navigation app has focus
        // OEM may choose to show their default cluster view
} else {
       // focusOwnerPackageNames
       // Use the PackageManager to retrieve the cluster activity for the package(s)
       // returned in focusOwnerPackageNames
}

...

נספח: שימוש באפליקציה לדוגמה

ב-AOSP יש אפליקציה לדוגמה שמטמיעה את Navigation State API.

כדי להריץ את האפליקציה לדוגמה הזו:

  1. פיתוח וטעינה של Android Auto ב-HU נתמך. משתמשים בהוראות הספציפיות למכשיר שלכם ליצירה ולעדכון של Android. להוראות, ראו שימוש בלוחות עזר.
  2. מחברים מסך משני פיזי ל-HU (אם יש תמיכה) או מפעילים את המסך המשני הווירטואלי של ה-HU:
    1. בוחרים באפשרות מצב פיתוח באפליקציית ההגדרות.
    2. עוברים אל הגדרות > מערכת > מתקדם > אפשרויות למפתחים > סימולציה של מסכים משניים.
  3. מפעילים מחדש את HU
  4. כדי להפעיל את אפליקציית KitchenSink:
    1. פותחים את חלונית ההזזה.
    2. עוברים אל Inst. Cluster.
    3. לוחצים על התחלת המטא-נתונים.

KitchenSink מבקש להתמקד ב-NAVIGATION, שמורה לשירות DirectRenderingCluster להציג ממשק משתמש מדומה באשכול המכשירים.