ב-Android Automotive, הקול נחשב למרכיב חיוני לאינטראקציות בטוחות בזמן הנהיגה, ואחת הדרכים הבטוחות ביותר שבהן משתמשים יכולים לקיים אינטראקציה עם מערכת Android Automotive OS בזמן הנהיגה. כתוצאה מכך, הרחבנו את ממשקי ה-API של עוזרות הקול של Android (כולל VoiceInteractionSession
) כדי לאפשר לעוזרות הקול לבצע עבור המשתמשים משימות שקשה לבצע בזמן הנהיגה.
התכונה הקשה לקריאה מאפשרת למסייעות הקוליות לקרוא הודעות טקסט ולענות להן בשם המשתמש, כשהמשתמש מבצע פעולה כלשהי בתגובה להתראות על הודעות. כדי לספק את הפונקציונליות הזו, אפשר לשלב עוזרת קולית עם CarVoiceInteractionSession
.
ב-Automotive, התראות שפורסמו במרכז ההתראות ומסומנות בתווית INBOX
או INBOX_IN_GROUP
(למשל, הודעות SMS) כוללות לחצן הפעלה. המשתמש יכול ללחוץ על הפעלה כדי שהעוזרת הקולית שנבחרה תקריא את ההתראה, וגם להשיב לה באמצעות הקול.
איור 1. התראה עם לחצן הפעלה להקשה כדי לקרוא.
שילוב עם CarVoiceInteractionSession
בקטעים הבאים מוסבר איך לשלב עוזרת קול עם CarVoiceInteractionSession
.
תמיכה באינטראקציות קוליות
אפליקציות שמספקות שירותי אינטראקציה קולית ברכב חייבות לשלב את עצמן עם האינטראקציות הקוליות הקיימות ב-Android. למידע נוסף, ראו Google Assistant ל-Android (למעט VoiceInteractionSession
). כל הרכיבים של Voice Interaction API נשארים זהים לאלה שמופעלים במכשירים ניידים, אבל CarVoiceInteractionSession
(המתואר בקטע הטמעת CarVoiceInteractionSession) מחליף את VoiceInteractionSession
. מידע נוסף זמין בדפים הבאים:
הטמעת CarVoiceInteractionSession
CarVoiceInteractionSession
מציג ממשקי API שאפשר להשתמש בהם כדי לאפשר לעוזרי הקול לקרוא הודעות טקסט בקול רם ואז
לענות להודעות האלה מטעם המשתמש.
ההבדל העיקרי בין הכיתות CarVoiceInteractionSession
ו-VoiceInteractionSession
הוא ש-CarVoiceInteractionSession
מעביר את הפעולה ב-onShow
כדי שעוזר הקול יוכל לזהות את ההקשר של הבקשה של המשתמש ברגע ש-CarVoiceInteractionSession
מתחיל סשן. הפרמטרים של onShow
לכל כיתה מפורטים בטבלה הבאה:
CarVoiceInteractionSession | VoiceInteractionSession |
---|---|
onShow מקבל את שלושת הפרמטרים הבאים:
|
onShow מקבל את שני הפרמטרים הבאים:
|
שינויים ב-Android 10
החל מ-Android 10, הפלטפורמה קוראת ל-VoiceInteractionService.onGetSupportedVoiceActions
כדי לזהות אילו פעולות נתמכות. העוזרת הקולית מבטלת את VoiceInteractionService.onGetSupportedVoiceActions
ומטמיעה אותה, כפי שמוצג בדוגמה הבאה:
public class MyInteractionService extends VoiceInteractionService { private static final ListSUPPORTED_VOICE_ACTIONS = Arrays.asList( CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION); @Override public Set onGetSupportedVoiceActions(@NonNull Set voiceActions) { Set result = new HashSet<>(voiceActions); result.retainAll(SUPPORTED_VOICE_ACTIONS); return result; } }
הפעולות התקינות מתוארות בטבלה הבאה. פרטים על כל פעולה זמינים במאמר תרשים רצף.
פעולה | עומס נתונים צפוי | הפעולה הצפויה של האינטראקציה הקולית |
---|---|---|
VOICE_ACTION_READ_NOTIFICATION |
קוראים את ההודעות למשתמש, ואז מפעילים את הכוונה 'סימון כהודעה שנקראה' חזרה כשההודעות נקראו בהצלחה. אפשר גם לבקש מהמשתמש להשיב. | |
VOICE_ACTION_REPLY_NOTIFICATION |
ניתן לחלק למקטעים עם מפתח.KEY_NOTIFICATION
שממופה אל StatusBarNotification .נדרשת android.permission.BIND_NOTIFICATION_LISTENER_SERVICE . |
מבקשים מהמשתמש לומר את הודעת התשובה, מזינים את הודעת התשובה בשדה RemoteInputReply של ה-intent בהמתנה ואז מפעילים את ה-intent בהמתנה. |
VOICE_ACTION_HANDLE_EXCEPTION |
מחרוזת עם מפתח.KEY_EXCEPTION
שממופה לערך ExceptionValue
(מתואר בקטע ערכים חריגים).KEY_FALLBACK_ASSISTANT_ENABLED שממופה לערך בוליאני. אם הערך הוא true , אסיסטנט החלופות שיכול לטפל בבקשה של המשתמש הושבת. |
הפעולה הצפויה שצריך לבצע לגבי החריגה מוגדרת במסמכי התיעוד של החריגה. |
ערכים חריגים
EXCEPTION_NOTIFICATION_LISTENER_PERMISSIONS_MISSING
מציין לעוזרת הקולית שחסרה לה ההרשאה Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE
, ומבקש לקבל את ההרשאה הזו מהמשתמש.
שליחת בקשה להרשאת מאזין להתראות
אם לאסיסטנטת הקול שמוגדרת כברירת מחדל אין הרשאה להאזין להתראות, יכול להיות שFallbackAssistant
של הפלטפורמה (אם היא מופעלת על ידי יצרן הרכב) יקרא את ההודעה בקול לפני שהסייעת הקולנית תקבל הודעה לבקש את ההרשאה. כדי לקבוע אם FallbackAssistant
מופעלת ושהיא קראה את ההודעה, העוזרת הקולית צריכה לבדוק את הערך הבוליאני KEY_FALLBACK_ASSISTANT_ENABLED
בתוכן הייעודי.
בפלטפורמה מומלץ שעוזר הקול יוסיף לוגיקה של הגבלת קצב לבקשות של ההרשאה הזו. כך אפשר לכבד את המשתמשים שלא רוצים להעניק לשעון ההרשאה הזו ומעדיפים שהFallbackAssistant
יקריא הודעות טקסט. הצגת בקשה למשתמש לאישור בכל פעם שהוא לוחץ על הפעלה בהתראה על הודעה יכולה להוביל לחוויית משתמש שלילית. הפלטפורמה לא מטילה מגבלות קצב בשם העוזר הקולי.
כשמבקשים את ההרשאה להאזנה להתראות, העוזרת הקולית צריכה להשתמש ב-CarUxRestrictionsManager
כדי לקבוע אם המשתמש חונה או נוהג. אם המשתמש נוהג, תופיע התראה עם הוראות להענקת ההרשאה. כך תוכלו לעזור למשתמש (ולזכור אותו) להעניק את ההרשאה כשהיא בטוחה יותר.
עבודה עם StatusBarNotification
הערך של StatusBarNotification
שמשויך לפעולות הקוליות 'קריאה' ו'תשובה' תמיד מופיע בהתראה על הודעה שתואמת לרכב, כפי שמתואר בקטע עדכון המשתמשים על הודעות. יכול להיות שבחלק מההתראות לא יופיע הכוונה 'תשובה בהמתנה', אבל בכל ההתראות יופיעו הכוונות בהמתנה מסוג 'סימון כנקרא'.
כדי לייעל את האינטראקציות עם ההתראות, אפשר להשתמש ב-NotificationPayloadHandler
, שמספק שיטות לחילוץ הודעות מההתראה ולכתיבת הודעות התשובה ל-intent בהמתנה המתאים של ההתראה. אחרי שעוזרת הקול מקריאה את ההודעה, היא חייבת להפעיל את הכוונה 'סימון כנקרא'.
עמידה בתנאי הקבלה של 'הקשה כדי לקרוא'
רק VoiceInteractionSession
מבין עוזרות הקול שמוגדרות כברירת מחדל יקבלו התראה כשמשתמש מפעיל את הפעולה הקולית כדי לקרוא הודעות ולענות להן. כפי שצוין למעלה, לעוזר הדיגיטלי שמוגדר כברירת מחדל צריכה להיות גם ההרשאה 'האזנה להתראות'.
דיאגרמות רצף
בתרשים הבא מוצגים תהליכי הלוגיקה של CarVoiceInteractionSession actions
:
איור 2. תרשים רצף של VOICE_ACTION_READ_NOTIFICATION.
במקרה של איור 3, מומלץ להשתמש באפליקציה עם הגבלת קצב של בקשות הרשאה:
איור 3. תרשים רצף של VOICE_ACTION_REPLY_NOTIFICATION.
איור 4. תרשים רצף של VOICE_ACTION_HANDLE_EXCEPTION.
קריאת שם האפליקציה
אם אתם רוצים שהעוזרת הקולית תקריא את שם אפליקציית ההודעות בקול רם במהלך הקריאה של ההודעה (לדוגמה, "דני מ-Hangouts אמר…"), תוכלו ליצור פונקציה כמו זו שמוצגת בדוגמת הקוד הבאה כדי לוודא שהעוזרת קורא את השם הנכון:
@Nullable String getMessageApplicationName(Context context, StatusBarNotification statusBarNotification) { ApplicationInfo info = getApplicationInfo(context, statusBarNotification.getPackageName()); if (info == null) return null; Notification notification = statusBarNotification.getNotification(); // Sometimes system packages will post on behalf of other apps, so check this // field for a system app notification. if (isSystemApp(info) && notification.extras.containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)) { return notification.extras.getString(Notification.EXTRA_SUBSTITUTE_APP_NAME); } else { PackageManager pm = context.getPackageManager(); return String.valueOf(pm.getApplicationLabel(info)); } } @Nullable ApplicationInfo getApplicationInfo(Context context, String packageName) { final PackageManager pm = context.getPackageManager(); ApplicationInfo info; try { info = pm.getApplicationInfo(packageName, 0); } catch (PackageManager.NameNotFoundException e) { return null; } return info; } boolean isSystemApp(ApplicationInfo info) { return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; }