Home | History | Annotate | Download | only in voiceenrollment
      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 
     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      */
     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
    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
    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 
    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