פיתוח אפליקציות

כדי להטמיע אפליקציה לאינטראקציה קולית (VIA), מבצעים את השלבים הבאים:

  1. יוצרים שלד של VIA.
  2. (אופציונלי) הטמעת תהליך הגדרה או כניסה.
  3. (אופציונלי) הטמעת מסך הגדרות.
  4. מצהירים על ההרשאות הנדרשות בקובץ המניפסט.
  5. הטמעה של ממשק משתמש של לוח קולי.
  6. הטמעה של זיהוי דיבור (חייבת לכלול הטמעה של RecognitionService API).
  7. מטמיעים את האמירה (אפשר גם להטמיע את TextToSpeech API).
  8. מטמיעים את אספקת הפקודות. אפשר לעיין בתוכן הזה במאמר ביצוע פקודות.

בקטעים הבאים מוסבר איך לבצע כל אחד מהשלבים שצוינו למעלה.

יצירת שלד של VIA

מניפסטים

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

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myvoicecontrol">
    ...

  <application ... >
    <service android:name=".MyInteractionService"
        android:label="@string/app_name"
        android:permission="android.permission.BIND_VOICE_INTERACTION"
        android:process=":interactor">
      <meta-data
          android:name="android.voice_interaction"
          android:resource="@xml/interaction_service" />
      <intent-filter>
        <action android:name=
          "android.service.voice.VoiceInteractionService" />
      </intent-filter>
    </service>
  </application>
</manifest>

בדוגמה הזו:

  • ממשקי VIA חייבים לחשוף שירות שמרחיב את VoiceInteractionService, עם מסנן Intent לפעולה VoiceInteractionService.SERVICE_INTERFACE ("android.service.voice.VoiceInteractionService").
  • לשירות הזה צריכה להיות הרשאת חתימה במערכת BIND_VOICE_INTERACTION.
  • השירות הזה צריך לכלול קובץ מטא-נתונים android.voice_interaction עם הפרטים הבאים:

    res/xml/interaction_service.xml

    <voice-interaction-service
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:sessionService=
          "com.example.MyInteractionSessionService"
        android:recognitionService=
          "com.example.MyRecognitionService"
        android:settingsActivity=
          "com.example.MySettingsActivity"
        android:supportsAssist="true"
        android:supportsLaunchVoiceAssistFromKeyguard="true"
        android:supportsLocalInteraction="true" />

פרטים על כל שדה מופיעים במאמר R.styleable#VoiceInteractionService. מכיוון שכל ממשקי ה-VIA הם גם שירותים לזיהוי קולי, אתם צריכים לכלול גם את הפרטים הבאים במניפסט:

AndroidManifest.xml

<manifest ...>
  <uses-permission android:name="android.permission.RECORD_AUDIO"/>
  <application ...>
    ...
    <service android:name=".RecognitionService" ...>
      <intent-filter>
        <action android:name="android.speech.RecognitionService" />
        <category android:name="android.intent.category.DEFAULT" />
      </intent-filter>
      <meta-data
        android:name="android.speech"
        android:resource="@xml/recognition_service" />
    </service>
  </application>
</manifest>

שירותי זיהוי קולי דורשים גם את רכיב המטא-נתונים הבא:

res/xml/recognition_service.xml

<recognition-service
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:settingsActivity="com.example.MyRecognizerSettingsActivity" />

VoiceInteractionService,‏ VoiceInteractionSessionService ו-VoiceInteractionSession

בתרשים הבא מוצג מחזור החיים של כל אחת מהישויות האלה:

מחזורי חיים

איור 1. מחזורי חיים

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

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

בצורה הפשוטה ביותר, הטמעה של VoiceInteractionService תיראה כך:

public class MyVoiceInteractionService extends VoiceInteractionService {
    private static final List<String> SUPPORTED_VOICE_ACTIONS =
        Arrays.asList(
            CarVoiceInteractionSession.VOICE_ACTION_READ_NOTIFICATION,
            CarVoiceInteractionSession.VOICE_ACTION_REPLY_NOTIFICATION,
            CarVoiceInteractionSession.VOICE_ACTION_HANDLE_EXCEPTION
    );

    @Override
    public void onReady() {
        super.onReady();
        // TODO: Setup hotword detector
    }

    @NonNull
    @Override
    public Set<String> onGetSupportedVoiceActions(
            @NonNull Set<String> voiceActions) {
        Set<String> result = new HashSet<>(voiceActions);
        result.retainAll(SUPPORTED_VOICE_ACTIONS);
        return result;
    }
    ...
}

ההטמעה של VoiceInteractionService#onGetSupportedVoiceActions() נדרשת כדי לטפל בתכונה 'לוחצים כדי לקרוא' של העוזר הדיגיטלי. המערכת משתמשת ב-VoiceInteractionSessionService כדי ליצור VoiceInteractionSession ולקיים איתו אינטראקציה. האחריות היחידה שלו היא להתחיל סשנים חדשים כשמבקשים.

public class MyVoiceInteractionSessionService extends VoiceInteractionSessionService {
    @Override
    public VoiceInteractionSession onNewSession(Bundle args) {
        return new MyVoiceInteractionSession(this);
    }
}

לבסוף, רוב העבודה מתבצעת ב-VoiceInteractionSession. יכול להיות שנעשה שימוש חוזר במופע יחיד של סשן כדי להשלים כמה אינטראקציות של משתמשים. ב-AAOS, יש רכיב עזר CarVoiceInteractionSession שעוזר להטמיע חלק מהפונקציות הייחודיות לרכב.

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {

    public InteractionSession(Context context) {
        super(context);
    }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        closeSystemDialogs();
        // TODO: Unhide UI and update UI state
        // TODO: Start processing audio input
    }
    ...
}

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

הטמעה של תהליך הגדרה או כניסה

ההגדרה והכניסה יכולות להתבצע:

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

פרטים על חוויית המשתמש המומלצת והנחיות ויזואליות מופיעים במאמר עוזרים דיגיטליים שנטענו מראש: הנחיות לחוויית משתמש.

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

המשתמש תמיד יכול לבחור ב-VIA שלא הוגדר כראוי. הסיבות האפשריות לכך:

  • המשתמש דילג על אשף ההגדרה כולו או דילג על שלב ההגדרה של האינטראקציה הקולית.
  • המשתמש בחר ב-VIA שונה מזה שהוגדר במהלך צירוף המכשיר.

בכל מקרה, יש כמה דרכים שבהן VoiceInteractionService יכול לעודד את המשתמש להשלים את ההגדרה:

  • תזכורת להתראה.
  • תשובה קולית אוטומטית כשהמשתמש מנסה להשתמש בה.

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

תזכורת

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

תזכורת

איור 2. תזכורת

כך יפעל התהליך הזה:

תהליך התזכורת לשליחת התראות

איור 3. תהליך התזכורת לשליחת התראות

תשובה קולית

זהו התהליך הכי פשוט ליישום. הוא מתחיל בהשמעת דיבור באמצעות קריאה חוזרת (callback) של VoiceInteractionSession#onShow(), מסביר למשתמש מה צריך לעשות ואז שואל אותו (אם ההגדרה מותרת בהתאם למצב ההגבלה של חוויית המשתמש) אם הוא רוצה להתחיל את תהליך ההגדרה. אם אי אפשר לבצע את ההגדרה כרגע, תסביר גם את זה.

הגדרה בשימוש הראשון

תמיד יש אפשרות שהמשתמש יפעיל VIA שלא הוגדר כראוי. במקרים כאלה:

  1. להודיע למשתמש באופן מילולי על המצב (לדוגמה, "כדי לפעול בצורה תקינה, עליך לבצע כמה שלבים… ").
  2. אם מנוע הגבלות חוויית המשתמש מאפשר זאת (ראו UX_RESTRICTIONS_NO_SETUP), שואלים את המשתמש אם הוא רוצה להתחיל בתהליך ההגדרה ואז פותחים את מסך ההגדרות של ה-VIA.
  3. אחרת (לדוגמה, אם המשתמש נוהג), כדאי להשאיר למשתמש הודעה שיוכל ללחוץ על האפשרות כשהדבר יהיה בטוח.

פיתוח מסכי הגדרה של אינטראקציה קולית

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

הנחיות כלליות:

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

הטמעה של מסך הגדרות

שילוב הגדרות

איור 4. שילוב הגדרות

מסכי ההגדרות הם פעילויות רגילות ב-Android. אם מיושם, נקודת הכניסה שלהם צריכה להיות מוצהרת ב-res/xml/interaction_service.xml כחלק ממניפסטים של VIA (ראו מניפסטים). בקטע 'הגדרות' אפשר להמשיך את ההגדרה ולהיכנס לחשבון (אם המשתמש לא השלים אותה), או להציע את האפשרות יציאה מהחשבון או החלפת משתמש אם צריך. בדומה למסכי ההגדרה שמתוארים למעלה, המסכים האלה צריכים:

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

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

אפשר לחלק את ההרשאות שנדרשות ל-VIA לשלוש קטגוריות:

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

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

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

בקשת הרשאות כחלק ממסך ההגדרות

בקשות להרשאות מסוכנות נשלחות באמצעות שיטת ActivityCompat#requestPermission() רגילה (או שיטה שוות ערך). פרטים על אופן בקשת ההרשאות זמינים במאמר בנושא בקשת הרשאות לאפליקציה.

שליחת בקשה להרשאות

איור 5. שליחת בקשה להרשאות

הרשאה למאזין להתראות

כדי להטמיע את תהליך ה-TTR, צריך להגדיר את ממשקי ה-VIA כמאזינים להודעות. זו לא הרשאה כשלעצמה, אלא הגדרה שמאפשרת למערכת לשלוח התראות למאזינים רשומים. כדי לדעת אם ל-VIA ניתנה גישה למידע הזה, אפליקציות יכולות:

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

private void requestNotificationListenerAccess() {
    Intent intent = new Intent(Settings
        .ACTION_NOTIFICATION_LISTENER_SETTINGS);
    intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
    startActivity(intent);
}

הטמעה של ממשק משתמש של לוחית קול

כש-VoiceInteractionSession מקבל קריאה חוזרת (callback) של onShow(), הוא יכול להציג ממשק משתמש של לוחית קולית. הנחיות חזותיות והנחיות לגבי חוויית המשתמש בהטמעה של לוח קולי זמינות במאמר ממשקי Assistant שנטענו מראש: הנחיות לגבי חוויית המשתמש.

הצגת לוחית השם

איור 6. הצגת לוחית השם

יש שתי אפשרויות להטמעת ממשק המשתמש הזה:

  • שינוי של VoiceInteractionSession#onCreateContentView()
  • הפעלת פעילות באמצעות VoiceInteractionSession#startAssistantActivity()

שימוש ב-onCreateContentView()

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

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {
    private View mVoicePlate;
    

    @Override
    public View onCreateContentView() {
        mVoicePlate = inflater.inflate(R.layout.voice_plate, null);
        
   }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        // TODO: Update UI state to "listening"
        mVoicePlate.setVisibility(View.VISIBLE);
    }

    @Override
    public void onHide() {
        mVoicePlate.setVisibility(View.GONE);
    }
    
}

כשמשתמשים בשיטה הזו, כדאי לשנות את VoiceInteractionSession#onComputeInsets() כדי להתחשב באזורים מוסתרים בממשק המשתמש.

שימוש ב-startAssistantActivity()

במקרה כזה, VoiceInteractionSession מעביר את הטיפול בממשק המשתמש של לוחית הקול לפעילות רגילה. כשמשתמשים באפשרות הזו, הטמעה של VoiceInteractionSession callback צריכה להשבית את היצירה של חלון התוכן שמוגדר כברירת מחדל (ראו שימוש ב-onCreateContentView()) ב-onPrepareShow(). בשעה VoiceInteractionSession#onShow(), הסשן יתחיל את הפעילות של לוח הקול באמצעות VoiceInteractionSession#startAssistantActivity(). ה-method הזה מאתחל את ממשק המשתמש עם הגדרות החלון המתאימות ודגלי הפעילות.

public class MyVoiceInteractionSession extends CarVoiceInteractionSession {
    

    @Override
    public void onPrepareShow(Bundle args, int showFlags) {
        super.onPrepareShow(args, showFlags);
        setUiEnabled(false);
    }

    @Override
    protected void onShow(String action, Bundle args, int showFlags) {
        closeSystemDialogs();
        Intent intent = new Intent(getContext(), VoicePlateActivity.class);
        intent.putExtra(VoicePlateActivity.EXTRA_ACTION, action);
        intent.putExtra(VoicePlateActivity.EXTRA_ARGS, args);
        startAssistantActivity(intent);
    }

    
}

כדי לשמור על תקשורת בין הפעילות הזו לבין VoiceInteractionSession, יכול להיות שיידרש סט של כוונות פנימיות או שירותים מקושרים. לדוגמה, כשמפעילים את VoiceInteractionSession#onHide(), הסשן צריך להיות מסוגל להעביר את הבקשה הזו לפעילות.

חשוב. ב-Automotive, רק פעילויות עם הערות מיוחדות או פעילויות שמופיעות ב "רשימת ההיתרים" של UXR יכולות להיות מוצגות בזמן הנהיגה. זה נכון גם לגבי פעילויות שהתחילו עם VoiceInteractionSession#startAssistantActivity(). חשוב לזכור להוסיף הערות לפעילות באמצעות <meta-data android:name="distractionOptimized" android:value="true"/> או לכלול את הפעילות הזו במפתח <meta-data android:name="distractionOptimized" android:value="true"/> של הקובץ /packages/services/Car/service/res/values/config.xml.systemActivityWhitelist מידע נוסף זמין במאמר הנחיות בנושא הסחת דעת של נהגים.

הטמעה של זיהוי קולי

בקטע הזה מוסבר איך להטמיע זיהוי דיבור באמצעות זיהוי של מילות הפעלה. מילת הפעלה היא מילת טריגר שמשמשת להתחלת שאילתה או פעולה חדשה באמצעות הקול. לדוגמה, "Ok Google" או "Hey Google".

זיהוי מילת הפעלה ב-DSP

מערכת Android מספקת גישה לגלאי מילות הפעלה שפועל תמיד ברמת ה-DSP באמצעות AlwaysOnHotwordDetector. דרך להטמיע זיהוי של מילת הפעלה עם שימוש נמוך במעבד. השימוש בפונקציונליות הזו מחולק לשני חלקים:

  • יצירת אובייקט של AlwaysOnHotwordDetector.
  • הרשמה של מודל צליל לזיהוי מילת הפעלה.

הטמעה של VoiceInteractionService יכולה ליצור גלאי מילות הפעלה באמצעות VoiceInteractionService#createAlwaysOnHotwordDetector(), העברת ביטוי מפתח ולוקאל שהמשתמש רוצה להשתמש בהם לזיהוי. כתוצאה מכך, האפליקציה מקבלת קריאה חוזרת onAvailabilityChanged() עם אחד מהערכים האפשריים הבאים:

  • STATE_HARDWARE_UNAVAILABLE. יכולת DSP לא זמינה במכשיר. במקרה כזה, נעשה שימוש בזיהוי מילת הפעלה בתוכנה.
  • STATE_HARDWARE_UNSUPPORTED. אין תמיכה ב-DSP באופן כללי, אבל DSP לא תומך בשילוב הנתון של ביטוי מפתח ולוקאל. האפליקציה יכולה לבחור להשתמש בזיהוי מילת הפעלה באמצעות תוכנה.
  • STATE_HARDWARE_ENROLLED. זיהוי מילת ההפעלה מוכן ואפשר להפעיל אותו על ידי קריאה לשיטה startRecognition().
  • STATE_HARDWARE_UNENROLLED. מודל קול לביטוי המפתח המבוקש לא זמין, אבל אפשר להירשם.

אפשר להירשם לזיהוי מילת הפעלה של מודלים של צלילים באמצעות IVoiceInteractionManagerService#updateKeyphraseSoundModel(). אפשר לרשום במערכת כמה מודלים בו-זמנית, אבל רק מודל אחד משויך ל-AlwaysOnHotwordDetector. יכול להיות שהזיהוי של מילת ההפעלה באמצעות DSP לא יהיה זמין בכל המכשירים. מפתחי VIA צריכים לבדוק את יכולות החומרה באמצעות שיטה getDspModuleProperties(). דוגמת קוד להרשמה של מודלים של צלילים מופיעה במאמר VoiceEnrollment/src/com/android/test/voiceenrollment/EnrollmentUtil.java. מידע על זיהוי בו-זמני של מילות הפעלה זמין במאמר Concurrent capture (הקלטה בו-זמנית).

זיהוי מילת הפעלה בתוכנה

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

שני הקבועים האלה הם @hide וזמינים רק לאפליקציות בחבילה.

ניהול של קלט אודיו וזיהוי קול

קלט אודיו יוטמע באמצעות המחלקות MediaRecorder. מידע נוסף על השימוש ב-API הזה זמין במאמר סקירה כללית על MediaRecorder. גם שירותי אינטראקציה קולית צפויים להיות הטמעות של מחלקות RecognitionService כל אפליקציה במערכת שנדרשת לה זיהוי קולי משתמשת ב- כדי לגשת ליכולת הזו. כדי לבצע זיהוי קולי ולקבל גישה למיקרופון, לממשקי VIA צריכה להיות android.permission.RECORD_AUDIO. אפליקציות שגשת למימוש של RecognitionService צריכות להחזיק גם בהרשאה הזו.

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

גישה לפלט אודיו

כשה-VIA מוכן לספק תשובות מילוליות, חשוב לפעול לפי ההנחיות הבאות: