בדף הזה מוסבר איך לעבד קלט של חוגה ב-VHAL, איך להגדיר את ה-build כך שיכלול את שירות החוגה ואיך להתאים אישית את חוויית השימוש בחוגה בכל האפליקציות. לגבי אפליקציות OEM שהותקנו מראש, כמו מרכז אפליקציות שסופק על ידי OEM, אפשר לעיין במאמר בנושא ספריית ממשק המשתמש של הרכב (car-ui-library).
VHAL
בקר סיבובי תומך בפעולות הבאות:
- הסטה למעלה, למטה, שמאלה או ימינה.
- סיבוב בכיוון השעון ונגד כיוון השעון.
- לוחצים על הכפתור האמצעי.
- לוחצים על הלחצן 'הקודם'.
- לוחצים על לחצן דף הבית.
- לוחצים על לחצנים אחרים, כמו 'טלפון' ו'מדיה'.
מידע נוסף על מאפייני המערכת ועל int32Values זמין בhardware/interfaces/automotive/vehicle/2.0/types.hal.
ה-VHAL צריך לטפל בפעולות האלה:
נדנוד
כשמשתמש מזיז את בקר הסיבוב ימינה, ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT עם הערך int32Values כדי לשלוח אירוע ל-Android:
ACTION_DOWNKEYCODE_SYSTEM_NAVIGATION_RIGHT- התצוגה של היעד.
כשמשחררים את בקר הסיבוב, ה-VHAL צריך להשתמש באותו נכס ובאותו קוד מקש עם ACTION_UP. לשינויים בכיוונים אחרים צריך להשתמש בקודי המקשים המתאימים.
אין קודי מקשים לאלכסונים, אבל ה-VHAL יכול לשלב אירוע אופקי ואנכי כדי ליצור אלכסון אם החומרה תומכת באלכסונים. לדוגמה, אם מזיזים את התמונה למעלה ולצד שמאל, התוצאה צריכה להיות:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWNHW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWN
בכל סדר (ואחריו) שחרור של בקר הסיבוב אמור להפיק:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UPHW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
יכול להיות שהמשתמש דוחף את בקר הסיבוב בכיוון ניצב לפני שהוא משחרר אותו. לדוגמה, התרחיש הבא:
אמור להיווצר רצף האירועים הבא:
HW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_DOWNHW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_DOWNHW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_LEFT ACTION_UPHW_KEY_INPUT KEYCODE_SYSTEM_NAVIGATION_UP ACTION_UP
לא אמורים להיווצר אירועים של חזרה בזמן שמחזיקים את בקר הסיבוב בכיוון אחד.
סיבוב
כשמשתמש מסובב את בקר הסיבוב בכיוון השעון בשינון אחד (קליק), ה-VHAL
צריך להשתמש במאפיין HW_ROTARY_INPUT עם הערך int32Values
כדי לשלוח אירוע ל-Android:
ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION- שקע אחד (1).
- התצוגה של היעד.
חותמת הזמן של האירוע צריכה להיות מוגדרת כזמן שחלף בננו-שניות.
סיבוב אחד (1) נגד כיוון השעון צריך ליצור את אותו אירוע, אבל עם הערך -1 למספר השקעים.
אם מתרחשים כמה מעצורים של סיבוב באותו כיוון ברצף מהיר, ה-VHAL צריך לשלב את המעצורים לאירוע אחד כדי לא להעמיס על המערכת יותר מדי אירועים.
במקרה כזה, חותמת הזמן של האירוע צריכה להיות הרגע שבו התרחשה עצירת הסיבוב הראשונה.
הערך int32Values צריך לכלול את מספר הננו-שניות בין כל שקע עוקב של הסיבוב.
לדוגמה, רצף הסיבובים הבא:
- בזמן t0, המשתמש מסובב את הגלגל עם השקעים נגד כיוון השעון.
- בזמן t0 + 5 ns, המשתמש סיובב את הגלגל המרכזי נגד כיוון השעון.
- בזמן t0 + 8 ns, המשתמש סיובב את הגלגל בסיבוב אחד נגד כיוון השעון.
צריך ליצור את האירוע הזה:
- נכס:
HW_ROTARY_INPUT - חותמת זמן:
t0 int32Values:ROTARY_INPUT_TYPE_SYSTEM_NAVIGATION- -3 (שלושה סיבובים נגד כיוון השעון).
- התצוגה של היעד.
- 5 ננו-שניות בין השקע הראשון לשני.
- 3 ננו-שניות בין השלב השני לשלב השלישי.
הכפתור המרכזי
כשמשתמש לוחץ על הלחצן המרכזי, ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT
עם int32Values הבא כדי לשלוח אירוע ל-Android:
ACTION_DOWNKEYCODE_DPAD_CENTER- התצוגה של היעד.
כשמשחררים את בקר הסיבוב, ה-VHAL צריך להשתמש באותו מאפיין ובאותו קוד מקש עם ACTION_UP.
לא ליצור אירועים חוזרים כשמחזיקים את הלחצן המרכזי.
הכפתור "הקודם"
כשמשתמש לוחץ על הלחצן 'הקודם', ה-VHAL צריך להשתמש במאפיין HW_KEY_INPUT
עם int32Values הבא כדי לשלוח אירוע ל-Android:
ACTION_DOWNKEYCODE_BACK- התצוגה של היעד.
כשמשחררים את בקר הסיבוב, ה-VHAL צריך להשתמש באותו מאפיין ובאותו קוד מקש עם ACTION_UP.
לא אמורים להיווצר אירועים חוזרים בזמן שהכפתור המרכזי מוחזק.
לחצן דף הבית
מפעילים את הלחצן הראשי כמו שמפעילים את לחצן החזרה, אבל משתמשים ב-KEYCODE_HOME במקום ב-KEYCODE_BACK.
כפתורים אחרים
אם בבקר הסיבובי יש כפתורים נוספים, ה-VHAL יכול לטפל בהם בכל דרך שהיצרן רוצה, כי הם לא נחשבים לחלק מהבקר הסיבובי מנקודת המבט של Android.
בדרך כלל, המערכת מתייחסת אליהם כמו ללחצני 'הקודם' ו'מסך הבית', אבל עם קודי מקשים שונים.
לדוגמה, KEYCODE_CALL או KEYCODE_MUSIC.
תצורת build
ניווט סיבובי מסופק על ידי שירות נגישות שנקרא RotaryService.
כדי לכלול את השירות הזה בקובץ האימג' של המערכת במכשיר, מוסיפים את השורה הבאה לקובץ ה-makefile:
PRODUCT_PACKAGES += CarRotaryController
כדאי גם לכלול את החבילות הבאות בגרסאות ניפוי הבאגים:
RotaryPlaygroundאפליקציית הפניה לחוגה (ראו RotaryPlayground).RotaryIMEהדגמה של IME סיבובי (ראו עורכי שיטות קלט).CarRotaryImeRROשכבת-העל שלRotaryIME.
שירות החוגה מופעל אוטומטית כשהמכשיר מופעל וכשיש מעבר בין משתמשים. כך המשתמש יוכל להשתמש בבקר הסיבובי במהלך ההגדרה.
אם אתם משתמשים באותו 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:
-
car_ui_focus_history_cache_type:- הזיכרון מטמון מושבת.
- תוקף המטמון יפוג אחרי זמן מה (ראו בהמשך).
- התוקף של הנתונים במטמון לא יפוג לעולם.
-
car_ui_focus_history_expiration_period_ms: מספר אלפיות השנייה לפני שתוקף המטמון יפוג אם סוג המטמון מוגדר ל-2 (ראו למעלה).
מטמון ההיסטוריה של אזור המיקוד
(Android 11 QPR3, Android 11 Car, Android 12)
במטמון הזה נשמר היסטוריה של דחיפות, כך שאם תדחפו בכיוון ההפוך, המיקוד יחזור לאותו FocusArea. אפשר להגדיר את המטמון הזה על ידי שימוש במשאבים הבאים של car-ui-library:
-
car_ui_focus_area_history_cache_type:- הזיכרון מטמון מושבת.
- התוקף של הנתונים במטמון יפוג אחרי זמן מה (ראו בהמשך).
- הזיכרון מטמון לא יפוג לעולם.
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)
יצרן ה-OEM יכול לבטל שתי הגדרות של משאבי מספרים שלמים ב-RotaryService כדי לציין אם יש האצה, כמו האצת עכבר, לסיבוב:
-
rotation_acceleration_3x_ms: מרווח הזמן (באלפיות השנייה) שמשמש להחלטה אם Google צריכה להאיץ את סיבוב הבקר כדי להגיע לנקודת עצירה בסיבוב. אם המרווח בין השלב הזה לבין השלב הקודם של הסיבוב קטן מהערך הזה, הוא ייחשב כשלושה שלבים של סיבוב. כדי להשבית את ההאצה של 3x מגדירים את הערך ל-2147483647. -
rotation_acceleration_2x_ms: דומה ל-rotation_acceleration_3x_ms. משמש להאצה פי 2. מגדירים את הערך2147483647כדי להשבית את ההאצה הכפולה.
ההאצה פועלת בצורה הטובה ביותר כשיש חותמות זמן נפרדות לכל שקע של סיבוב, כפי שנדרש על ידי VHAL. אם הם לא זמינים, RotaryService מניח שהשקעים של הסיבוב מרווחים באופן שווה.
/** * 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. יצרן ה-OEM יכול להוסיף שכבת-על של 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 כדי לקבוע איך יודגש הפוקוס בתצוגות עם הדגשת פוקוס לא מלבנית (למשל, עגולה או בצורת גלולה) ובאפליקציות שמשתמשות בערכת נושא שלא נגזרת מ-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: עובי המתאר.
לפעמים נותנים לכפתור צבע רקע אחיד כדי למשוך את תשומת הלב של המשתמש, כמו בדוגמה שמוצגת. יכול להיות שיהיה קשה לראות את ההדגשה של המיקוד.
במצב כזה, המפתח יכול לציין הדגשה מותאמת אישית של המיקוד באמצעות צבעים משניים:
- (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
אפשר להגדיר שכל אחד מהצבעים יהיה שקוף, ואפשר להגדיר שכל אחד מהממדים יהיה אפס אם, לדוגמה, רוצים רק מילוי או רק קו מתאר.
הדגשה של אזור ההתמקדות
(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 שלcar_ui_focus_area_background_highlight.
עורכי שיטות קלט
עורכי שיטות קלט (IME) הם שיטות קלט. לדוגמה, מקלדת וירטואלית.
(Android 11 QPR3, Android 11 Car, Android 12)
יצרן ה-OEM צריך להוסיף שכבת-על למשאב המחרוזת 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)
אם ה-OEM יצר IME במיוחד עבור חוגה, הוא צריך לציין את ComponentName שלו במשאב rotary_input_method. אם המשאב הזה מוצג בשכבת-על, נעשה שימוש ב-IME שצוין בכל פעם שהמשתמש מקיים אינטראקציה עם יחידת הראש באמצעות הדחיפה, הסיבוב והלחצן המרכזי של בקר הסיבוב. כשמשתמש נוגע במסך, נעשה שימוש ב-IME הקודם. ללחצן 'הקודם' (וללחצנים אחרים בבקר הסיבובי) אין השפעה על בחירת IME. אם המשאב הזה לא מוצג בשכבת-על, לא מתבצעת החלפה של IME. Carboard לא תומך בחוגה, ולכן המשתמש לא יכול להזין טקסט באמצעות בקר החוגה אם יצרן הציוד המקורי לא סיפק IME של חוגה.
RotaryIME הוא IME להדגמה עם חוגה. הוא אמנם בסיסי, אבל הוא מספיק כדי לנסות את ההחלפה האוטומטית של IME שמתוארת למעלה. קוד המקור של RotaryIME
נמצא ב-packages/apps/Car/tests/RotaryIME/.
תזכורות מחוץ למסך
כברירת מחדל, כשמשתמש מנסה להזיז את החלון אל מחוץ לקצה המסך, לא קורה כלום. יצרן הציוד המקורי יכול להגדיר מה יקרה בכל אחד מארבעת הכיוונים על ידי ציון כל שילוב של:
- פעולה גלובלית שהוגדרה על ידי
AccessibilityService. לדוגמה:GLOBAL_ACTION_BACK. - קוד מפתח, כמו
KEYCODE_BACK. - כוונת המשתמש להפעיל פעילות שמיוצגת ככתובת 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: מערך של Intent להפעלת פעילות כשמשתמשים מזיזים את המסך למעלה, למטה, שמאלה או ימינה מקצה המסך. אם הרכיב הרלוונטי במערך הזה ריק, לא מופעלת פעילות.
הגדרות אחרות
מומלץ להשתמש במקורות המידע הבאים של 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_horizontaldimen resource ב-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: ערך מספרי שמייצג את מספר המילישניות שצריך ללחוץ לחיצה ארוכה על הלחצן המרכזי כדי להפעיל אותו. הערך אפס מציין שצריך להשתמש בערך ברירת המחדל של המערכת לזמן הקצוב לתפוגה של לחיצה ארוכה. זהו ערך ברירת המחדל.