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

כדי להטמיע אפליקציה לאינטראקציה קולית (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 (ראו מניפסטים). בקטע 'הגדרות' אפשר להמשיך את ההגדרה ולהיכנס לחשבון (אם המשתמש לא השלים אותה), או להציע את האפשרות יציאה מהחשבון או החלפת משתמש אם צריך. בדומה למסכי ההגדרה שמתוארים למעלה, המסכים האלה צריכים:

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

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

אפשר לחלק את ההרשאות שנדרשות ל-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"/> או לכלול את הפעילות הזו במפתח systemActivityWhitelist של קובץ /packages/services/Car/service/res/values/config.xml. מידע נוסף זמין במאמר הנחיות בנושא הסחת דעת של נהגים.

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

בקטע הזה מוסבר איך להטמיע זיהוי דיבור באמצעות זיהוי של מילות הפעלה. מילת הפעלה היא מילת טריגר שמשמשת להתחלת שאילתה או פעולה חדשה באמצעות הקול. לדוגמה, "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 כל אפליקציה במערכת שנדרשת לה זיהוי קולי משתמשת ב-API הזה כדי לגשת ליכולת הזו. כדי לבצע זיהוי קולי ולקבל גישה למיקרופון, לממשקי VIA צריכה להיות android.permission.RECORD_AUDIO. אפליקציות שגשת למימוש של RecognitionService צריכות לקבל גם את ההרשאה הזו.

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

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

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