191097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn/** 291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Copyright (C) 2014 The Android Open Source Project 391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * 491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Licensed under the Apache License, Version 2.0 (the "License"); 591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * you may not use this file except in compliance with the License. 691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * You may obtain a copy of the License at 791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * 891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * http://www.apache.org/licenses/LICENSE-2.0 991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * 1091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Unless required by applicable law or agreed to in writing, software 1191097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * distributed under the License is distributed on an "AS IS" BASIS, 1291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * See the License for the specific language governing permissions and 1491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * limitations under the License. 1591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn */ 1691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 1791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornpackage android.service.voice; 1891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 1991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.annotation.SdkConstant; 2091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.app.Service; 21fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackbornimport android.content.ComponentName; 2291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.content.Context; 2391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.content.Intent; 24d7018200312e4e4dc3f67cf33dc90bf7ce585844Sandeepimport android.hardware.soundtrigger.KeyphraseEnrollmentInfo; 2518f0d357f9693fe787a3e3777d8fdf01357a6e3fDianne Hackbornimport android.os.Bundle; 26fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackbornimport android.os.Handler; 2791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.os.IBinder; 28fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackbornimport android.os.Message; 2991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.os.RemoteException; 3091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport android.os.ServiceManager; 31fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackbornimport android.provider.Settings; 326daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 3322968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddharthaimport com.android.internal.annotations.VisibleForTesting; 3491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornimport com.android.internal.app.IVoiceInteractionManagerService; 3591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 366df952ec2208714d3206c54987eb388aee799be6Sandeep Siddharthaimport java.io.FileDescriptor; 376df952ec2208714d3206c54987eb388aee799be6Sandeep Siddharthaimport java.io.PrintWriter; 38dcf3068fcb55f101680e70a8a6f84f3b2c9cb1e3Sandeep Siddharthaimport java.util.Locale; 396df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha 40f7a13df899c30ddddbbf63274bc28174f6391f29Sandeep Siddhartha 41c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn/** 42c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * Top-level service of the current global voice interactor, which is providing 43d7c0395d26694c594c3e64b16ab647c971aeb422Dianne Hackborn * support for hotwording etc. 44c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * The current VoiceInteractionService that has been selected by the user is kept 45c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * always running by the system, to allow it to do things like listen for hotwords 46d7c0395d26694c594c3e64b16ab647c971aeb422Dianne Hackborn * in the background. 47c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * 48c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * <p>Because this service is always running, it should be kept as lightweight as 49c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn * possible. Heavy-weight operations (including showing UI) should be implemented 50d7c0395d26694c594c3e64b16ab647c971aeb422Dianne Hackborn * in the associated {@link android.service.voice.VoiceInteractionSessionService} 51d7c0395d26694c594c3e64b16ab647c971aeb422Dianne Hackborn * that only runs while the operation is active. 52c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn */ 5391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackbornpublic class VoiceInteractionService extends Service { 5491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn /** 5591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * The {@link Intent} that must be declared as handled by the service. 5691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * To be supported, the service must also require the 5791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * {@link android.Manifest.permission#BIND_VOICE_INTERACTION} permission so 5891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * that other applications can not abuse it. 5991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn */ 6091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION) 6191097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn public static final String SERVICE_INTERFACE = 6291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn "android.service.voice.VoiceInteractionService"; 6391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 6491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn /** 6591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * Name under which a VoiceInteractionService component publishes information about itself. 6691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * This meta-data should reference an XML resource containing a 6791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * <code><{@link 6891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn * android.R.styleable#VoiceInteractionService voice-interaction-service}></code> tag. 6991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn */ 7091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn public static final String SERVICE_META_DATA = "android.voice_interaction"; 7191097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 7291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn IVoiceInteractionService mInterface = new IVoiceInteractionService.Stub() { 73fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn @Override public void ready() { 74fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn mHandler.sendEmptyMessage(MSG_READY); 75fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 766daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha @Override public void shutdown() { 776daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHandler.sendEmptyMessage(MSG_SHUTDOWN); 786daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 796daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha @Override public void soundModelsChanged() { 806daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHandler.sendEmptyMessage(MSG_SOUND_MODELS_CHANGED); 816daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 8291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn }; 8391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 84fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn MyHandler mHandler; 85fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn 8691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn IVoiceInteractionManagerService mSystemService; 8791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 886daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha private final Object mLock = new Object(); 896daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 90e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha private KeyphraseEnrollmentInfo mKeyphraseEnrollmentInfo; 91e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha 926daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha private AlwaysOnHotwordDetector mHotwordDetector; 936daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 94fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn static final int MSG_READY = 1; 956daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha static final int MSG_SHUTDOWN = 2; 966daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha static final int MSG_SOUND_MODELS_CHANGED = 3; 97fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn 98fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn class MyHandler extends Handler { 99fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn @Override 100fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn public void handleMessage(Message msg) { 101fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn switch (msg.what) { 102fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn case MSG_READY: 103fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn onReady(); 104fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn break; 1056daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha case MSG_SHUTDOWN: 1066daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha onShutdownInternal(); 1076daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha break; 1086daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha case MSG_SOUND_MODELS_CHANGED: 1096daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha onSoundModelsChangedInternal(); 1106daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha break; 111fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn default: 112fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn super.handleMessage(msg); 113fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 114fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 115fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 116fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn 117fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn /** 118fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn * Check whether the given service component is the currently active 119fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn * VoiceInteractionService. 120fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn */ 121fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn public static boolean isActiveService(Context context, ComponentName service) { 122fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn String cur = Settings.Secure.getString(context.getContentResolver(), 123fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn Settings.Secure.VOICE_INTERACTION_SERVICE); 124fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn if (cur == null || cur.isEmpty()) { 125fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn return false; 126fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 127fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn ComponentName curComp = ComponentName.unflattenFromString(cur); 128fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn if (curComp == null) { 129fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn return false; 130fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 131e2c020a449cf1de10230d2ac31a083f342aa75c8Barnaby James return curComp.equals(service); 132fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 133fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn 134fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn /** 135fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn * Initiate the execution of a new {@link android.service.voice.VoiceInteractionSession}. 136fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn * @param args Arbitrary arguments that will be propagated to the session. 137fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn */ 138c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn public void startSession(Bundle args) { 139fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn if (mSystemService == null) { 140fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn throw new IllegalStateException("Not available until onReady() is called"); 141fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 14291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn try { 143c03c9167c2d9a1e22fb2b176b00a0524177fb037Dianne Hackborn mSystemService.startSession(mInterface, args); 14491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } catch (RemoteException e) { 14591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } 14691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } 14791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 14891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn @Override 14991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn public void onCreate() { 15091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn super.onCreate(); 151fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn mHandler = new MyHandler(); 15291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } 15391097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn 15491097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn @Override 15591097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn public IBinder onBind(Intent intent) { 15691097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn if (SERVICE_INTERFACE.equals(intent.getAction())) { 15791097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn return mInterface.asBinder(); 15891097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } 15991097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn return null; 16091097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn } 161e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha 162e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha /** 163fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn * Called during service initialization to tell you when the system is ready 1646daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * to receive interaction from it. You should generally do initialization here 1656daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * rather than in {@link #onCreate()}. Methods such as {@link #startSession(Bundle)} and 166dcf3068fcb55f101680e70a8a6f84f3b2c9cb1e3Sandeep Siddhartha * {@link #createAlwaysOnHotwordDetector(String, Locale, android.service.voice.AlwaysOnHotwordDetector.Callback)} 1676daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * will not be operational until this point. 168fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn */ 169fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn public void onReady() { 170fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn mSystemService = IVoiceInteractionManagerService.Stub.asInterface( 171fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn ServiceManager.getService(Context.VOICE_INTERACTION_MANAGER_SERVICE)); 172fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn mKeyphraseEnrollmentInfo = new KeyphraseEnrollmentInfo(getPackageManager()); 173fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 174fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn 1756daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha private void onShutdownInternal() { 1766daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha onShutdown(); 1776daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // Stop any active recognitions when shutting down. 1786daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // This ensures that if implementations forget to stop any active recognition, 1796daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // It's still guaranteed to have been stopped. 1806daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // This helps with cases where the voice interaction implementation is changed 1816daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // by the user. 1826daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha safelyShutdownHotwordDetector(); 1836daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 1846daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 1856daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha /** 1866daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * Called during service de-initialization to tell you when the system is shutting the 1876daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * service down. 1885e33fb057c20b84418d96574abe861e9d05956ebSandeep Siddhartha * At this point this service may no longer be the active {@link VoiceInteractionService}. 1896daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha */ 1906daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha public void onShutdown() { 1916daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 1926daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 1936daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha private void onSoundModelsChangedInternal() { 1946daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha synchronized (this) { 1956daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha if (mHotwordDetector != null) { 1966daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // TODO: Stop recognition if a sound model that was being recognized gets deleted. 1976daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHotwordDetector.onSoundModelsChanged(); 1986daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 1996daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2006daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2016daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 202fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn /** 2036daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * Creates an {@link AlwaysOnHotwordDetector} for the given keyphrase and locale. 2046daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * This instance must be retained and used by the client. 2056daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * Calling this a second time invalidates the previously created hotword detector 2066daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * which can no longer be used to manage recognition. 2076daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha * 208d7018200312e4e4dc3f67cf33dc90bf7ce585844Sandeep * @param keyphrase The keyphrase that's being used, for example "Hello Android". 209d7018200312e4e4dc3f67cf33dc90bf7ce585844Sandeep * @param locale The locale for which the enrollment needs to be performed. 210d7018200312e4e4dc3f67cf33dc90bf7ce585844Sandeep * @param callback The callback to notify of detection events. 211d7018200312e4e4dc3f67cf33dc90bf7ce585844Sandeep * @return An always-on hotword detector for the given keyphrase and locale. 212e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha */ 2136daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector( 214dcf3068fcb55f101680e70a8a6f84f3b2c9cb1e3Sandeep Siddhartha String keyphrase, Locale locale, AlwaysOnHotwordDetector.Callback callback) { 215fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn if (mSystemService == null) { 216fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn throw new IllegalStateException("Not available until onReady() is called"); 217fee756ff91ab4d8f0e09ddb050d22d88ebb66ae7Dianne Hackborn } 2186daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha synchronized (mLock) { 2196daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // Allow only one concurrent recognition via the APIs. 2206daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha safelyShutdownHotwordDetector(); 2216daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback, 2226daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mKeyphraseEnrollmentInfo, mInterface, mSystemService); 2236daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2246daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha return mHotwordDetector; 225e912ac012e7146e9b0e8589bd9d88790e55372e3Sandeep Siddhartha } 22622968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha 22722968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha /** 22822968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha * @return Details of keyphrases available for enrollment. 22922968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha * @hide 23022968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha */ 23122968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha @VisibleForTesting 23222968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha protected final KeyphraseEnrollmentInfo getKeyphraseEnrollmentInfo() { 23322968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha return mKeyphraseEnrollmentInfo; 23422968950b814e66a6aa119ea92ae648884cbe0d9Sandeep Siddhartha } 2356daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha 2366daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha private void safelyShutdownHotwordDetector() { 2376daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha try { 2386daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha synchronized (mLock) { 2396daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha if (mHotwordDetector != null) { 2406daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHotwordDetector.stopRecognition(); 2416daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHotwordDetector.invalidate(); 2426daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha mHotwordDetector = null; 2436daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2446daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2456daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } catch (Exception ex) { 2466daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha // Ignore. 2476daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2486daae9622672e0b38fc2efed29f68061d749caccSandeep Siddhartha } 2496df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha 2506df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha @Override 2516df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 2526df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha pw.println("VOICE INTERACTION"); 2536df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha synchronized (mLock) { 2546df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha pw.println(" AlwaysOnHotwordDetector"); 2556df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha if (mHotwordDetector == null) { 2566df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha pw.println(" NULL"); 2576df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha } else { 2586df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha mHotwordDetector.dump(" ", pw); 2596df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha } 2606df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha } 2616df952ec2208714d3206c54987eb388aee799be6Sandeep Siddhartha } 26291097de49b0f683b00e26a75dbc0ac6082344137Dianne Hackborn} 263