• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.test.voiceenrollment;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.hardware.soundtrigger.KeyphraseEnrollmentInfo;
22 import android.hardware.soundtrigger.SoundTrigger;
23 import android.hardware.soundtrigger.SoundTrigger.Keyphrase;
24 import android.hardware.soundtrigger.SoundTrigger.KeyphraseSoundModel;
25 import android.os.RemoteException;
26 import android.os.ServiceManager;
27 import android.service.voice.AlwaysOnHotwordDetector;
28 import android.util.Log;
29 
30 import com.android.internal.app.IVoiceInteractionManagerService;
31 
32 /**
33  * Utility class for the enrollment operations like enroll;re-enroll & un-enroll.
34  */
35 public class EnrollmentUtil {
36     private static final String TAG = "TestEnrollmentUtil";
37 
38     /**
39      * Activity Action: Show activity for managing the keyphrases for hotword detection.
40      * This needs to be defined by an activity that supports enrolling users for hotword/keyphrase
41      * detection.
42      */
43     public static final String ACTION_MANAGE_VOICE_KEYPHRASES =
44             KeyphraseEnrollmentInfo.ACTION_MANAGE_VOICE_KEYPHRASES;
45 
46     /**
47      * Intent extra: The intent extra for the specific manage action that needs to be performed.
48      * Possible values are {@link AlwaysOnHotwordDetector#MANAGE_ACTION_ENROLL},
49      * {@link AlwaysOnHotwordDetector#MANAGE_ACTION_RE_ENROLL}
50      * or {@link AlwaysOnHotwordDetector#MANAGE_ACTION_UN_ENROLL}.
51      */
52     public static final String EXTRA_VOICE_KEYPHRASE_ACTION =
53             KeyphraseEnrollmentInfo.EXTRA_VOICE_KEYPHRASE_ACTION;
54 
55     /**
56      * Intent extra: The hint text to be shown on the voice keyphrase management UI.
57      */
58     public static final String EXTRA_VOICE_KEYPHRASE_HINT_TEXT =
59             KeyphraseEnrollmentInfo.EXTRA_VOICE_KEYPHRASE_HINT_TEXT;
60     /**
61      * Intent extra: The voice locale to use while managing the keyphrase.
62      */
63     public static final String EXTRA_VOICE_KEYPHRASE_LOCALE =
64             KeyphraseEnrollmentInfo.EXTRA_VOICE_KEYPHRASE_LOCALE;
65 
66     /** Simple recognition of the key phrase */
67     public static final int RECOGNITION_MODE_VOICE_TRIGGER =
68             SoundTrigger.RECOGNITION_MODE_VOICE_TRIGGER;
69     /** Trigger only if one user is identified */
70     public static final int RECOGNITION_MODE_USER_IDENTIFICATION =
71             SoundTrigger.RECOGNITION_MODE_USER_IDENTIFICATION;
72 
73     private final IVoiceInteractionManagerService mModelManagementService;
74 
EnrollmentUtil()75     public EnrollmentUtil() {
76         mModelManagementService = IVoiceInteractionManagerService.Stub.asInterface(
77                 ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE));
78     }
79 
80     /**
81      * Adds/Updates a sound model.
82      * The sound model must contain a valid UUID,
83      * exactly 1 keyphrase,
84      * and users for which the keyphrase is valid - typically the current user.
85      *
86      * @param soundModel The sound model to add/update.
87      * @return {@code true} if the call succeeds, {@code false} otherwise.
88      */
addOrUpdateSoundModel(KeyphraseSoundModel soundModel)89     public boolean addOrUpdateSoundModel(KeyphraseSoundModel soundModel) {
90         if (!verifyKeyphraseSoundModel(soundModel)) {
91             return false;
92         }
93 
94         int status = SoundTrigger.STATUS_ERROR;
95         try {
96             status = mModelManagementService.updateKeyphraseSoundModel(soundModel);
97         } catch (RemoteException e) {
98             Log.e(TAG, "RemoteException in updateKeyphraseSoundModel", e);
99         }
100         return status == SoundTrigger.STATUS_OK;
101     }
102 
103     /**
104      * Gets the sound model for the given keyphrase, null if none exists.
105      * This should be used for re-enrollment purposes.
106      * If a sound model for a given keyphrase exists, and it needs to be updated,
107      * it should be obtained using this method, updated and then passed in to
108      * {@link #addOrUpdateSoundModel(KeyphraseSoundModel)} without changing the IDs.
109      *
110      * @param keyphraseId The keyphrase ID to look-up the sound model for.
111      * @param bcp47Locale The locale for with to look up the sound model for.
112      * @return The sound model if one was found, null otherwise.
113      */
114     @Nullable
getSoundModel(int keyphraseId, String bcp47Locale)115     public KeyphraseSoundModel getSoundModel(int keyphraseId, String bcp47Locale) {
116         if (keyphraseId <= 0) {
117             Log.e(TAG, "Keyphrase must have a valid ID");
118             return null;
119         }
120 
121         KeyphraseSoundModel model = null;
122         try {
123             model = mModelManagementService.getKeyphraseSoundModel(keyphraseId, bcp47Locale);
124         } catch (RemoteException e) {
125             Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
126         }
127 
128         if (model == null) {
129             Log.w(TAG, "No models present for the gien keyphrase ID");
130             return null;
131         } else {
132             return model;
133         }
134     }
135 
136     /**
137      * Deletes the sound model for the given keyphrase id.
138      *
139      * @param keyphraseId The keyphrase ID to look-up the sound model for.
140      * @return {@code true} if the call succeeds, {@code false} otherwise.
141      */
142     @Nullable
deleteSoundModel(int keyphraseId, String bcp47Locale)143     public boolean deleteSoundModel(int keyphraseId, String bcp47Locale) {
144         if (keyphraseId <= 0) {
145             Log.e(TAG, "Keyphrase must have a valid ID");
146             return false;
147         }
148 
149         int status = SoundTrigger.STATUS_ERROR;
150         try {
151             status = mModelManagementService.deleteKeyphraseSoundModel(keyphraseId, bcp47Locale);
152         } catch (RemoteException e) {
153             Log.e(TAG, "RemoteException in updateKeyphraseSoundModel");
154         }
155         return status == SoundTrigger.STATUS_OK;
156     }
157 
verifyKeyphraseSoundModel(KeyphraseSoundModel soundModel)158     private boolean verifyKeyphraseSoundModel(KeyphraseSoundModel soundModel) {
159         if (soundModel == null) {
160             Log.e(TAG, "KeyphraseSoundModel must be non-null");
161             return false;
162         }
163         if (soundModel.uuid == null) {
164             Log.e(TAG, "KeyphraseSoundModel must have a UUID");
165             return false;
166         }
167         if (soundModel.data == null) {
168             Log.e(TAG, "KeyphraseSoundModel must have data");
169             return false;
170         }
171         if (soundModel.keyphrases == null || soundModel.keyphrases.length != 1) {
172             Log.e(TAG, "Keyphrase must be exactly 1");
173             return false;
174         }
175         Keyphrase keyphrase = soundModel.keyphrases[0];
176         if (keyphrase.id <= 0) {
177             Log.e(TAG, "Keyphrase must have a valid ID");
178             return false;
179         }
180         if (keyphrase.recognitionModes < 0) {
181             Log.e(TAG, "Recognition modes must be valid");
182             return false;
183         }
184         if (keyphrase.locale == null) {
185             Log.e(TAG, "Locale must not be null");
186             return false;
187         }
188         if (keyphrase.text == null) {
189             Log.e(TAG, "Text must not be null");
190             return false;
191         }
192         if (keyphrase.users == null || keyphrase.users.length == 0) {
193             Log.e(TAG, "Keyphrase must have valid user(s)");
194             return false;
195         }
196         return true;
197     }
198 }
199