1 /* 2 * Copyright (C) 2020 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 android.media.voice; 18 19 import android.Manifest; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.RequiresPermission; 23 import android.annotation.SystemApi; 24 import android.annotation.TestApi; 25 import android.hardware.soundtrigger.SoundTrigger; 26 import android.os.Binder; 27 import android.os.RemoteException; 28 import android.os.ServiceSpecificException; 29 import android.util.Slog; 30 31 import com.android.internal.app.IVoiceInteractionManagerService; 32 33 import java.util.Locale; 34 import java.util.Objects; 35 36 /** 37 * This class provides management of voice based sound recognition models. Usage of this class is 38 * restricted to system or signature applications only. This allows OEMs to write apps that can 39 * manage voice based sound trigger models. 40 * Callers of this class are expected to have whitelist manifest permission MANAGE_VOICE_KEYPHRASES. 41 * Callers of this class are expected to be the designated voice interaction service via 42 * {@link Settings.Secure.VOICE_INTERACTION_SERVICE} or a bundled voice model enrollment application 43 * detected by {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. 44 * @hide 45 */ 46 @SystemApi 47 public final class KeyphraseModelManager { 48 private static final boolean DBG = false; 49 private static final String TAG = "KeyphraseModelManager"; 50 51 private final IVoiceInteractionManagerService mVoiceInteractionManagerService; 52 53 /** 54 * @hide 55 */ KeyphraseModelManager( IVoiceInteractionManagerService voiceInteractionManagerService)56 public KeyphraseModelManager( 57 IVoiceInteractionManagerService voiceInteractionManagerService) { 58 if (DBG) { 59 Slog.i(TAG, "KeyphraseModelManager created."); 60 } 61 mVoiceInteractionManagerService = voiceInteractionManagerService; 62 } 63 64 65 /** 66 * Gets the registered sound model for keyphrase detection for the current user. 67 * The keyphraseId and locale passed must match a supported model passed in via 68 * {@link #updateKeyphraseSoundModel}. 69 * If the active voice interaction service changes from the current user, all requests will be 70 * rejected, and any registered models will be unregistered. 71 * Caller must either be the active voice interaction service via 72 * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model 73 * enrollment application detected by 74 * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. 75 * 76 * @param keyphraseId The unique identifier for the keyphrase. 77 * @param locale The locale language tag supported by the desired model. 78 * @return Registered keyphrase sound model matching the keyphrase ID and locale. May be null if 79 * no matching sound model exists. 80 * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission 81 * or if the caller is not the active voice interaction service. 82 */ 83 @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 84 @Nullable getKeyphraseSoundModel(int keyphraseId, @NonNull Locale locale)85 public SoundTrigger.KeyphraseSoundModel getKeyphraseSoundModel(int keyphraseId, 86 @NonNull Locale locale) { 87 Objects.requireNonNull(locale); 88 try { 89 return mVoiceInteractionManagerService.getKeyphraseSoundModel(keyphraseId, 90 locale.toLanguageTag()); 91 } catch (RemoteException e) { 92 throw e.rethrowFromSystemServer(); 93 } 94 } 95 96 /** 97 * Add or update the given keyphrase sound model to the registered models pool for the current 98 * user. 99 * If a model exists with the same Keyphrase ID, locale, and user list. The registered model 100 * will be overwritten with the new model. 101 * If the active voice interaction service changes from the current user, all requests will be 102 * rejected, and any registered models will be unregistered. 103 * Caller must either be the active voice interaction service via 104 * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model 105 * enrollment application detected by 106 * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. 107 * 108 * @param model Keyphrase sound model to be updated. 109 * @throws ServiceSpecificException Thrown with error code if failed to update the keyphrase 110 * sound model. 111 * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission 112 * or if the caller is not the active voice interaction service. 113 */ 114 @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) updateKeyphraseSoundModel(@onNull SoundTrigger.KeyphraseSoundModel model)115 public void updateKeyphraseSoundModel(@NonNull SoundTrigger.KeyphraseSoundModel model) { 116 Objects.requireNonNull(model); 117 try { 118 int status = mVoiceInteractionManagerService.updateKeyphraseSoundModel(model); 119 if (status != SoundTrigger.STATUS_OK) { 120 throw new ServiceSpecificException(status); 121 } 122 } catch (RemoteException e) { 123 throw e.rethrowFromSystemServer(); 124 } 125 } 126 127 /** 128 * Delete keyphrase sound model from the registered models pool for the current user matching\ 129 * the keyphrase ID and locale. 130 * The keyphraseId and locale passed must match a supported model passed in via 131 * {@link #updateKeyphraseSoundModel}. 132 * If the active voice interaction service changes from the current user, all requests will be 133 * rejected, and any registered models will be unregistered. 134 * Caller must either be the active voice interaction service via 135 * {@link Settings.Secure.VOICE_INTERACTION_SERVICE}, or the caller must be a voice model 136 * enrollment application detected by 137 * {@link android.hardware.soundtrigger.KeyphraseEnrollmentInfo}. 138 * 139 * @param keyphraseId The unique identifier for the keyphrase. 140 * @param locale The locale language tag supported by the desired model. 141 * @throws ServiceSpecificException Thrown with error code if failed to delete the keyphrase 142 * sound model. 143 * @throws SecurityException Thrown when caller does not have MANAGE_VOICE_KEYPHRASES permission 144 * or if the caller is not the active voice interaction service. 145 */ 146 @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) deleteKeyphraseSoundModel(int keyphraseId, @NonNull Locale locale)147 public void deleteKeyphraseSoundModel(int keyphraseId, @NonNull Locale locale) { 148 Objects.requireNonNull(locale); 149 try { 150 int status = mVoiceInteractionManagerService.deleteKeyphraseSoundModel(keyphraseId, 151 locale.toLanguageTag()); 152 if (status != SoundTrigger.STATUS_OK) { 153 throw new ServiceSpecificException(status); 154 } 155 } catch (RemoteException e) { 156 throw e.rethrowFromSystemServer(); 157 } 158 } 159 160 /** 161 * Override the persistent enrolled model database with an in-memory 162 * fake for testing purposes. 163 * 164 * @param enabled - {@code true} if the model enrollment database should be overridden with an 165 * in-memory fake. {@code false} if the real, persistent model enrollment database should be 166 * used. 167 * @hide 168 */ 169 @RequiresPermission(Manifest.permission.MANAGE_VOICE_KEYPHRASES) 170 @TestApi setModelDatabaseForTestEnabled(boolean enabled)171 public void setModelDatabaseForTestEnabled(boolean enabled) { 172 try { 173 mVoiceInteractionManagerService.setModelDatabaseForTestEnabled(enabled, new Binder()); 174 } catch (RemoteException e) { 175 throw e.rethrowFromSystemServer(); 176 } 177 } 178 } 179