מדריך לשילוב עבור יצרני ציוד מקורי (OEM)

בדף הזה מוסבר איך לעבד קלט של גלגלות ב-VHAL, להגדיר את ה-build כך שיכלול את שירות הגלגלות ואיך להתאים אישית את חוויית השימוש בגלגלות בכל האפליקציות. למידע על אפליקציות OEM מותקנות מראש, כמו מרכז אפליקציות שסופק על ידי יצרן ציוד מקורי, ראו ספריית ממשק המשתמש שברכב (car-ui-library).

VHAL

בבורר רוטורי יש תמיכה בפעולות הבאות:

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

במסמכים של hardware/interfaces/automotive/vehicle/2.0/types.hal מפורט מידע על מאפייני המערכת ועל int32Values התואם.

VHAL צריך לטפל בפעולות הבאות:

נדנוד

כשהמשתמש דוחף את הלחצן הدوار ימינה, ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT עם הערך הבא של int32Values כדי לשלוח אירוע ל-Android:

  1. ACTION_DOWN
  2. KEYCODE_SYSTEM_NAVIGATION_RIGHT
  3. טירגוט לרשת המדיה.

כשהמשתמש משחרר את הבקר האלקטרוני, ה-VHAL צריך להשתמש באותו נכס ובאותו מפתח עם ACTION_UP. כדי להזיז את התמונה לכיוונים אחרים, צריך להשתמש בקודים המתאימים למקשות.

אין קודי מפתחות ללחיצות באלכסון, אבל ה-VHAL יכול לשלב אירוע אופקי ואנכי כדי ליצור אירוע באלכסון, אם החומרה תומכת בלחיצות באלכסון. לדוגמה, אם תזוזו למעלה ולשמאל, התוצאה אמורה להיות:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN

בכל סדר (ואחריו) שחרור של הבקר האלקטרוני אמור להניב:

  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  • HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

המשתמש יכול לדחוף את הבקר המסתובב בכיוון אנכי לפני שהוא משחרר אותו. לדוגמה, התרחיש הבא:

כיוון אנכי
איור 1. כיוון אנכי

הפעולה הזו אמורה ליצור את רצף האירועים הבא:

  1. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWN
  2. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
  3. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UP
  4. HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP

לא אמורים להיווצר אירועי repeat בזמן שהאחזור האוטומטי מוחזק בכיוון אחד.

סיבוב

כשהמשתמש מסובב את הבקר האלקטרוני בכיוון השעון בפסיק אחד (קליק), ה-VHAL צריך להשתמש בנכס HW_ROTARY_INPUT עם הערך הבא של int32Values כדי לשלוח אירוע ל-Android:

  1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
  2. נעילה אחת (1).
  3. טירגוט לרשת המדיה.

צריך להגדיר את חותמת הזמן של האירוע לזמן שחלף בננו-שניות.

סיבוב של קליק אחד נגד כיוון השעון אמור ליצור את אותו אירוע, אבל עם מספר קליקים של -1.

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

לדוגמה, רצף הסיבובים הבא:

  • בזמן t0, המשתמש סובב את הנעילה אחת נגד כיוון השעון.
  • בזמן t0 + 5 ns, המשתמש סובב את הלחצן אחד לאחור.
  • בזמן t0 + 8 ns, המשתמש סובב את הלחצן אחד נגד כיוון השעון.

צריך ליצור את האירוע הזה:

  • נכס: HW_ROTARY_INPUT
  • חותמת זמן: t0
  • int32Values:
    1. ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION
    2. -3 (שלושה נעילות נגד כיוון השעון).
    3. טירגוט לרשת המדיה.
    4. 5 ננו-שניות בין הנעילה הראשונה לשנייה.
    5. 3 ננו-שניות בין הנעילה השנייה לשלישית.

הכפתור המרכזי

כשהמשתמש לוחץ על הלחצן האמצעי, ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT עם int32Values הבא כדי לשלוח אירוע ל-Android:

  1. ACTION_DOWN
  2. KEYCODE_DPAD_CENTER
  3. טירגוט לרשת המדיה.

כשהמשתמש משחרר את הבקר האלקטרוני, ה-VHAL צריך להשתמש באותו נכס ובאותו קוד מפתח עם ACTION_UP.

לא ליצור אירועי חזרה כשמקישים לחיצה ארוכה על הלחצן המרכזי.

לחצן 'הקודם'

כשהמשתמש לוחץ על הלחצן 'הקודם', ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT עם הערך הבא של int32Values כדי לשלוח אירוע ל-Android:

  1. ACTION_DOWN
  2. KEYCODE_BACK
  3. טירגוט לרשת המדיה.

כשהמשתמש משחרר את הבקר האלקטרוני, ה-VHAL צריך להשתמש באותו נכס ובאותו קוד מפתח עם ACTION_UP.

לא אמורים להיווצר אירועי חזרה בזמן הלחיצה על הלחצן האמצעי.

לחצן 'דף הבית'

משתמשים בלחצן דף הבית כמו בלחצן 'הקודם', אבל מקישים על KEYCODE_HOME במקום על KEYCODE_BACK.

לחצנים אחרים

אם בבורר האלקטרוני יש לחצנים נוספים, ה-VHAL יכול לטפל בהם בכל דרך שה-OEM רוצה, כי הם לא נחשבים לחלק מהבורר האלקטרוני מבחינת Android. בדרך כלל, המערכת מטפלת בהם כמו בלחצנים 'הקודם' ו'דף הבית', אבל עם קודי מפתח שונים. לדוגמה: KEYCODE_CALL או KEYCODE_MUSIC.

הגדרת build

התכונה 'ניווט באמצעות לחצן מסתובב' מסופקת על ידי שירות נגישות שנקרא RotaryService. כדי לכלול את השירות הזה בתמונת המערכת של המכשיר, מוסיפים את השורה הבאה לקובץ ה-makefile:

PRODUCT_PACKAGES += CarRotaryController

מומלץ לכלול גם את החבילות הבאות ב-builds לניפוי באגים:

השירות המסתובב מופעל באופן אוטומטי כשהמכשיר מופעל וכשמתבצע מעבר של משתמש. כך המשתמש יוכל להשתמש בבורר במהלך ההגדרה.

אם אתם משתמשים באותו build למכוניות עם בקר רוטורי וללא בקר רוטורי, צריך להוסיף את CarRotaryController כפי שמתואר למעלה כדי שהקוד הנדרש יכלול ב-build. כדי למנוע הפעלה של השירות הרוטרי ברכב ללא גלגלים מסתובבים, יוצרים RRO סטטי כדי להוסיף שכבה על משאב המחרוזת rotaryService ב-packages/services/Car/service עם מחרוזת ריקה. תשתמשו באותו build, אבל תהיה לכם הגדרת מוצר נפרדת למכשירים מסתובבים ולא מסתובבים. רק האפשרות השנייה כוללת את שכבת-העל.

התאמה אישית

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

  • car-ui-library נמצאת ב-packages/apps/Car/libs/car-ui-lib
  • RotaryService נמצא ב-packages/apps/Car/RotaryController
  • Core נמצא ב-frameworks/base/core

היסטוריית הנדנודים

יצרני הציוד המקורי יכולים להגדיר אם כל אחד משני סוגי היסטוריית הדחיפה יופעל או לא, ואם כן, את גודל המטמון ואת מדיניות התפוגה. כל זה נעשה על ידי שינוי של משאבים שונים של car-ui-library.

מטמון ההיסטוריה של התמקדות

(Android 11 QPR3,‏ Android 11 Car,‏ Android 12)
המטמון הזה לכל FocusArea שומר את התצוגה האחרונה שבה התמקדו ב-FocusArea, כדי שאפשר יהיה להתמקד בה כשחוזרים ל-FocusArea. אפשר להגדיר את המטמון הזה על ידי שכבת-על של המשאבים הבאים של car-ui-library:

  • car_ui_focus_history_cache_type:
    1. המטמון מושבת.
    2. תוקף המטמון יפוג אחרי זמן מה (ראו בהמשך).
    3. התוקף של המטמון לא יפוג לעולם.
  • car_ui_focus_history_expiration_period_ms: מספר אלפיות השנייה לפני שתוקף המטמון יפוג אם סוג המטמון מוגדר לשניים (2) (ראו למעלה).

מטמון ההיסטוריה של FocusArea

(Android 11 QPR3,‏ Android 11 Car,‏ Android 12)
במטמון הזה מאוחסן היסטוריית הדחפים, כך שדחיפה בכיוון ההפוך יכולה להחזיר את המיקוד לאותו FocusArea. אפשר להגדיר את המטמון הזה על ידי שכבת-על של משאבי car-ui-library הבאים:

  • car_ui_focus_area_history_cache_type:
    1. המטמון מושבת.
    2. התוקף של המטמון יפוג לאחר זמן מה (ראו בהמשך).
    3. תוקף המטמון לא יפוג לעולם.
  • car_ui_focus_area_history_expiration_period_ms: מספר אלפיות השנייה לפני שתוקף המטמון יפוג אם סוג המטמון מוגדר כ-2 (ראו למעלה).
  • car_ui_clear_focus_area_history_when_rotating: האם למחוק את המטמון כשהמשתמש מסובב את הבקר.

סיבוב

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
יצרני ציוד מקורי יכולים לשנות שני משאבים שלמים ב-RotaryService כדי לציין אם יש תאוצה, כמו תאוצה של עכבר, לצורך סיבוב:

  • rotation_acceleration_3x_ms: מרווח הזמן (באלפיות שנייה) שמשמש להחלטה אם Google צריכה להאיץ את סיבוב הבקר כדי להפסיק את הסיבוב. אם המרווח בין הנעילה הזו לנעילה הקודמת של הסיבוב קטן מהערך הזה, הוא ייחשב כשלוש נעילות של סיבוב. כדי להשבית את האצת המהירות פי 3, מגדירים את הערך הזה ל-2147483647.
  • rotation_acceleration_2x_ms: דומה ל-rotation_acceleration_3x_ms. משמש להאצה פי 2. כדי להשבית את האצת המהירות פי 2, מגדירים את הערך כ-2147483647.

ההאצה פועלת בצורה הטובה ביותר כשיש חותמות זמן נפרדות לכל עצירה בתנועה, כפי שנדרש על ידי VHAL. אם הנתונים האלה לא זמינים, הפונקציה RotaryService מניחה שהעצירות של התנועה בכיוון ציר Z ממוקמות במרווחים שווים.

/**
     * Property to feed H/W rotary events to android
     *
     * int32Values[0] : RotaryInputType identifying which rotary knob rotated
     * int32Values[1] : number of detents (clicks), positive for clockwise,
     *                  negative for counterclockwise
     * int32Values[2] : target display defined in VehicleDisplay. Events not
     *                  tied to specific display must be sent to
     *                  VehicleDisplay#MAIN.
     * int32values[3 .. 3 + abs(number of detents) - 2]:
     *                  nanosecond deltas between pairs of consecutive detents,
     *                  if the number of detents is > 1 or < -1
     *
     * VehiclePropValue.timestamp: when the rotation occurred. If the number of
     *                             detents is > 1 or < -1, this is when the
     *                             first detent of rotation occurred.
     *
     * @change_mode VehiclePropertyChangeMode:ON_CHANGE
     * @data_enum RotaryInputType
     * @access VehiclePropertyAccess:READ
     */
    HW_ROTARY_INPUT = (
        0x0A20
        | VehiclePropertyGroup:SYSTEM
        | VehiclePropertyType:INT32_VEC
        | VehicleArea:GLOBAL),

הדגשת מיקוד

יצרני הציוד המקורי יכולים לשנות את ברירת המחדל של הדגשת המיקוד במסגרת Android ואת כמה משאבי הדגשת המיקוד ב-car-ui-library.

הדגשת מוקד ברירת המחדל

מסגרת Android מספקת הדגשה של ברירת מחדל של מוקד באמצעות המאפיין selectableItemBackground. ב-Theme.DeviceDefault, המאפיין הזה מתייחס ל-item_background.xml ב-Core. יצרני הציוד המקורי יכולים להוסיף שכבה על item_background.xml כדי לשנות את ברירת המחדל של drawable להדגשת המיקוד.

בדרך כלל, האובייקט הניתן לציור צריך להיות StateListDrawable, שמתאים את הרקע על סמך שילובים שונים של מצבים, כולל android:state_focused ו-android:state_pressed. כשהמשתמש משתמש בבורר המסתובב כדי למקד את התצוגה, הערך של android:state_focused יהיה true, אבל הערך של android:state_pressed יהיה false. אם המשתמש ילחץ על הלחצן המרכזי בבורר, הערכים של android:state_focused ו-android:state_pressed יהיו true כל עוד המשתמש ילחץ על הלחצן. כשהמשתמש ישחרר את הלחצן, רק android:state_focused יישארtrue.

ספריית car-ui-library משתמשת בעיצוב שמבוסס על Theme.DeviceDefault. כתוצאה מכך, שכבת-העל הזו משפיעה על אפליקציות שמשתמשות בספרייה הזו ועל אפליקציות שמשתמשות בכל נושא שמבוסס על Theme.DeviceDefault. היא לא תשפיע על אפליקציות שמשתמשות בעיצוב לא קשור, כמו Theme.Material.

התמקדות במשאבים של הדגשה ב-car-ui-library

יצרן הציוד המקורי יכול לשנות כמה משאבים של car-ui-library כדי לקבוע איך תראה ההדגשה של האזור הממוקד בתצוגות עם הדגשה של אזור ממוקד לא מלבנית (כמו עגולה או בצורת גלולה) ובאפליקציות שמשתמשות בנושא שלא נגזר מ-Theme.DeviceDefault. צריך להציג את המשאבים האלה בשכבה עליונה, כך שההדגשה של מוקד ההקלדה תהיה עקבית עם הקובץ הגרפי של הדגשת מוקד ההקלדה שמוגדר כברירת מחדל.

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
המשאבים הבאים משמשים לציון מתי התצוגה ממוקדת אבל לא לוחצים עליה:

  • car_ui_rotary_focus_fill_color: צבע המילוי.
  • car_ui_rotary_focus_stroke_color: צבע קו המתאר.
  • car_ui_rotary_focus_stroke_width: עובי המתאר.

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
המשאבים הבאים משמשים לציון מתי התצוגה ממוקדת וגם נלחצה:

  • car_ui_rotary_focus_pressed_fill_color: צבע המילוי.
  • car_ui_rotary_focus_pressed_stroke_color: צבע קו המתאר.
  • car_ui_rotary_focus_pressed_stroke_width: עובי המתאר.

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

כפתור עם רקע אחיד
איור 2. כפתור עם רקע אחיד

במקרה כזה, המפתח יכול לציין הדגשת מוקד בהתאמה אישית באמצעות צבעים משניים:
  • (Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
    car_ui_rotary_focus_fill_secondary_color
    car_ui_rotary_focus_stroke_secondary_color
  • (Android 12)
    car_ui_rotary_focus_pressed_fill_secondary_color
    car_ui_rotary_focus_pressed_stroke_secondary_color

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

הדגשת FocusArea

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
FocusArea יכול לצייר שני סוגים של הדגשה כשאחד מהצאצאים שלו מקבל את המיקוד. אפשר להשתמש בשתי התכונות יחד, אם רוצים. התכונה הזו מושבתת כברירת מחדל ב-AOSP, אבל אפשר להפעיל אותה על ידי שינוי משאבי car-ui-library:

  • car_ui_enable_focus_area_foreground_highlight: ציור הדגשה מעל FocusArea וצאצאיו. ב-AOSP, ה-drawable הזה הוא קו מתאר סביב ה-FocusArea. יצרני ציוד מקורי יכולים לשנות את קובץ ה-drawable‏ car_ui_focus_area_foreground_highlight.
  • car_ui_enable_focus_area_background_highlight: ציור הדגשה מעל FocusArea אבל מאחורי הצאצאים שלו. ב-AOSP, ה-drawable הזה הוא מילוי מוצק. יצרני ציוד מקורי יכולים לשנות את קובץ ה-drawable של car_ui_focus_area_background_highlight.

עורכי שיטות קלט

עורכי שיטות קלט (IME) הם שיטות קלט. לדוגמה, מקלדת שמופיעה במסך.

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
יצרני הציוד המקורי חייבים להוסיף שכבה של משאב המחרוזת default_touch_input_method ב-RotaryService כדי לציין את ComponentName של ה-IME המבוסס-מגע. לדוגמה, אם יצרן הציוד המקורי משתמש ב-IME שסופק עם Android Automotive, הוא צריך לציין את הערך com.google.android.apps.automotive.inputmethod/.InputMethodService.

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
אם יצרן הציוד המקורי יצר IME במיוחד למכשיר עם לחצן מסתובב, הוא צריך לציין את הערך של ComponentName במשאב rotary_input_method. אם המשאב הזה מופיע בשכבה עליונה, ה-IME שצוין ישמש בכל פעם שהמשתמש יהיה באינטראקציה עם יחידת הראש באמצעות הלחצן 'הזזה', הלחצן 'סיבוב' והלחצן 'מרכז' של הבקר המסתובב. כשהמשתמש נוגע במסך, המערכת משתמשת ב-IME הקודם. ללחצן 'הקודם' (וללחצנים אחרים בלחצן הסיבוב) אין השפעה על הבחירה של IME. אם המשאב הזה לא מוחלף, לא מתבצע מעבר בין IME. ב-Cardboard אין תמיכה בחוגה, ולכן המשתמש לא יכול להזין טקסט באמצעות הבקר החשמלי של החוגה אם יצרן הציוד המקורי לא סיפק IME לחוגה.

RotaryIME הוא IME להדגמה עם חוגה. הבדיקה הזו היא בסיסית, אבל מספיקה כדי לנסות את המעבר האוטומטי בין ממשקי ה-IME שמתואר למעלה. קוד המקור של RotaryIME אפשר למצוא ב-packages/apps/Car/tests/RotaryIME/.

דחיפה מחוץ למסך

כברירת מחדל, כשהמשתמש מנסה לדחוף את המסך מחוץ למסגרת, לא קורה כלום. יצרן הציוד המקורי יכול להגדיר מה יקרה בכל אחת מארבע האפשרויות על ידי ציון כל שילוב של:

  1. פעולה גלובלית שמוגדרת על ידי AccessibilityService. לדוגמה, GLOBAL_ACTION_BACK.
  2. קוד מפתח, כמו KEYCODE_BACK.
  3. כוונה להפעיל פעילות שמיוצגת ככתובת URL.

(Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
הערך מצוין על ידי שכבת-על של משאבי המערך הבאים ב-RotaryService:

  • off_screen_nudge_global_actions: מערך של פעולות גלובליות לביצוע כשהמשתמש דוחף למעלה, למטה, ימינה או שמאלה מחוץ לקצה המסך. אם האלמנט הרלוונטי במערך הזה הוא -1, לא מתבצעת פעולה גלובלית.
  • off_screen_nudge_key_codes: מערך של קודי מפתח של אירועי לחיצה להזרקה כשהמשתמש מזיז את האצבע למעלה, למטה, ימינה או שמאלה מחוץ לקצה המסך. לא מתבצעת הזרקה של אירועים אם האלמנט הרלוונטי במערך הזה הוא 0 (KEYCODE_UNKNOWN).
  • off_screen_nudge_intents: מערך של כוונות להפעלת פעילות כשהמשתמש מזיז את המסך למעלה, למטה, שמאלה או ימינה מהקצה. אם הרכיב הרלוונטי במערך הזה ריק, לא תתבצע הפעלה של פעילות.

הגדרות אחרות

צריך להוסיף שכבה של המשאבים הבאים מסוג RotaryService:

  • (Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
    config_showHeadsUpNotificationOnBottom: ערך בוליאני שמייצג אם התראות מראש צריכות להופיע בחלק התחתון של המסך במקום בחלק העליון. הערך הזה חייב להיות זהה לערך של המשאב הבוליאני config_showHeadsUpNotificationOnBottom ב-frameworks/base/packages/CarSystemUI/res/values/config.xml.
  • (Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
    notification_headsup_card_margin_horizontal: שוליים ימין ושמאל של חלון ההתראה הקופצת. הערך הזה חייב להיות זהה לערך של משאב המאפיין notification_headsup_card_margin_horizontal ב-packages/apps/Car/Notification/res/values/dimens.xml
  • (Android 12)
    excluded_application_overlay_window_titles: מערך של שמות של חלונות שלא צריך להתייחס אליהם כחלונות שכבת-על. הוא צריך לכלול שמות של חלונות של אפליקציות שמייצגים את TaskViews או את TaskDisplayAreas. כברירת מחדל, הרשימה הזו מכילה רק את 'מפות'.

אפשר להוסיף שכבה על המשאב RotaryService הבא:

  • (Android 11 QPR3, ‏ Android 11 Car,‏ Android 12)
    long_press_ms: ערך שלם שמייצג את מספר אלפיות השנייה שצריך ללחוץ על הלחצן האמצעי כדי להפעיל לחיצה ארוכה. הערך 0 מציין שצריך להשתמש בזמן הקצוב כברירת מחדל ללחיצה ארוכה. זהו ערך ברירת המחדל.