179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov/*
279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * Copyright (C) 2010 The Android Open Source Project
379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov *
479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * Licensed under the Apache License, Version 2.0 (the "License");
579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * you may not use this file except in compliance with the License.
679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * You may obtain a copy of the License at
779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov *
879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov *      http://www.apache.org/licenses/LICENSE-2.0
979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov *
1079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * Unless required by applicable law or agreed to in writing, software
1179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * distributed under the License is distributed on an "AS IS" BASIS,
1279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * See the License for the specific language governing permissions and
1479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * limitations under the License.
1579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov */
1679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
1779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovpackage android.speech;
1879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
1979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.content.ComponentName;
2079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.content.Context;
2179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.content.Intent;
2279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.content.ServiceConnection;
2379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.content.pm.ResolveInfo;
2479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.os.Bundle;
253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsovimport android.os.Handler;
2679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.os.IBinder;
273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsovimport android.os.Looper;
283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsovimport android.os.Message;
2979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.os.RemoteException;
305d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeauimport android.provider.Settings;
315d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeauimport android.text.TextUtils;
3279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport android.util.Log;
3379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsovimport java.util.LinkedList;
3579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsovimport java.util.List;
363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsovimport java.util.Queue;
3779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
3879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov/**
3979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * This class provides access to the speech recognition service. This service allows access to the
4079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov * speech recognizer. Do not instantiate this class directly, instead, call
412a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi * {@link SpeechRecognizer#createSpeechRecognizer(Context)}. This class's methods must be
422921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * invoked only from the main application thread.
432921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson *
442921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * <p>The implementation of this API is likely to stream audio to remote servers to perform speech
452921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * recognition. As such this API is not intended to be used for continuous recognition, which would
462921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * consume a significant amount of battery and bandwidth.
472921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson *
482921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * <p>Please note that the application must have {@link android.Manifest.permission#RECORD_AUDIO}
492921cee3048f7e64ba6645d50a1c1705ef9658f8Marc Wilson * permission to use this class.
5079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov */
512a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivipublic class SpeechRecognizer {
5279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** DEBUG value to enable verbose debug prints */
5379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    private final static boolean DBG = false;
5479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
5579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Log messages identifier */
562a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    private static final String TAG = "SpeechRecognizer";
5779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
5879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
59bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * Key used to retrieve an {@code ArrayList<String>} from the {@link Bundle} passed to the
6079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * {@link RecognitionListener#onResults(Bundle)} and
6179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * {@link RecognitionListener#onPartialResults(Bundle)} methods. These strings are the possible
6279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * recognition results, where the first element is the most likely candidate.
6379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
643da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final String RESULTS_RECOGNITION = "results_recognition";
65bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau
66bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau    /**
67bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * Key used to retrieve a float array from the {@link Bundle} passed to the
68bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * {@link RecognitionListener#onResults(Bundle)} and
69bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * {@link RecognitionListener#onPartialResults(Bundle)} methods. The array should be
70bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * the same size as the ArrayList provided in {@link #RESULTS_RECOGNITION}, and should contain
71bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * values ranging from 0.0 to 1.0, or -1 to represent an unavailable confidence score.
72bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * <p>
73bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * Confidence values close to 1.0 indicate high confidence (the speech recognizer is confident
74bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * that the recognition result is correct), while values close to 0.0 indicate low confidence.
75bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * <p>
76bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     * This value is optional and might not be provided.
77bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau     */
78bb7cf916b23c78dc640f8bdfb7ad5cd6b09c3636Mike LeBeau    public static final String CONFIDENCE_SCORES = "confidence_scores";
7979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
8079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Network operation timed out. */
813da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NETWORK_TIMEOUT = 1;
8279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
8379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Other network related errors. */
843da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NETWORK = 2;
8579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
8679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Audio recording error. */
873da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_AUDIO = 3;
8879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
8979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Server sends error status. */
903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_SERVER = 4;
9179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
9279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Other client side errors. */
933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_CLIENT = 5;
9479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
9579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** No speech input */
963da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_SPEECH_TIMEOUT = 6;
9779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
9879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** No recognition result matched. */
993da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NO_MATCH = 7;
10079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
10179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** RecognitionService busy. */
1023da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_RECOGNIZER_BUSY = 8;
1033da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Insufficient permissions */
1053da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_INSUFFICIENT_PERMISSIONS = 9;
1063da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1073da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** action codes */
1083da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_START = 1;
1093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_STOP = 2;
1103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_CANCEL = 3;
1113da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_CHANGE_LISTENER = 4;
1123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The actual RecognitionService endpoint */
1143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private IRecognitionService mService;
1153da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The connection to the actual service */
1173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private Connection mConnection;
1183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Context with which the manager was created */
1203da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final Context mContext;
12179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
12279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    /** Component to direct service intent to */
12379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    private final ComponentName mServiceComponent;
1243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Handler that will execute the main tasks */
1263da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private Handler mHandler = new Handler() {
1273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        @Override
1283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void handleMessage(Message msg) {
1293da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            switch (msg.what) {
1303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_START:
1313da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleStartListening((Intent) msg.obj);
1323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_STOP:
1343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleStopMessage();
1353da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_CANCEL:
1373da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleCancelMessage();
1383da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1393da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_CHANGE_LISTENER:
1403da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleChangeListener((RecognitionListener) msg.obj);
1413da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
1433da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
1443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    };
14579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
14679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1473da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Temporary queue, saving the messages until the connection will be established, afterwards,
1483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * only mHandler will receive the messages
14979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
1503da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final Queue<Message> mPendingTasks = new LinkedList<Message>();
1513da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1523da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The Listener that will receive all the callbacks */
1533da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final InternalListener mListener = new InternalListener();
15479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
15579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1562a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * The right way to create a {@code SpeechRecognizer} is by using
1572a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link #createSpeechRecognizer} static factory method
15879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
1592a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    private SpeechRecognizer(final Context context, final ComponentName serviceComponent) {
16079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        mContext = context;
16179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau        mServiceComponent = serviceComponent;
16279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
16379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
16479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1653da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Basic ServiceConnection that records the mService variable. Additionally, on creation it
1663da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * invokes the {@link IRecognitionService#startListening(Intent, IRecognitionListener)}.
16779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
16879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    private class Connection implements ServiceConnection {
16979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
1703da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void onServiceConnected(final ComponentName name, final IBinder service) {
1713da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            // always done on the application main thread, so no need to send message to mHandler
17279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mService = IRecognitionService.Stub.asInterface(service);
17379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "onServiceConnected - Success");
1743da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            while (!mPendingTasks.isEmpty()) {
1753da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mHandler.sendMessage(mPendingTasks.poll());
1763da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
17779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
17879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
17979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onServiceDisconnected(final ComponentName name) {
1803da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            // always done on the application main thread, so no need to send message to mHandler
18179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mService = null;
18279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mConnection = null;
1833da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mPendingTasks.clear();
18479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "onServiceDisconnected - Success");
18579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
18679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
18779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
18879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
18979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * Checks whether a speech recognition service is available on the system. If this method
1902a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * returns {@code false}, {@link SpeechRecognizer#createSpeechRecognizer(Context)} will
1913da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * fail.
19279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     *
1932a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context with which {@code SpeechRecognizer} will be created
19479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * @return {@code true} if recognition is available, {@code false} otherwise
19579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
19679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public static boolean isRecognitionAvailable(final Context context) {
19779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        final List<ResolveInfo> list = context.getPackageManager().queryIntentServices(
198cccd63c8e8e989a55cbeeb6c7d253a709139c223Valentin Kravtsov                new Intent(RecognitionService.SERVICE_INTERFACE), 0);
19979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        return list != null && list.size() != 0;
20079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
20179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
20279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
2032a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Factory method to create a new {@code SpeechRecognizer}. Please note that
2041168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called before dispatching any
2052a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * command to the created {@code SpeechRecognizer}, otherwise no notifications will be
2061168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * received.
2071168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
2082a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context in which to create {@code SpeechRecognizer}
2092a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @return a new {@code SpeechRecognizer}
21079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
2112a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    public static SpeechRecognizer createSpeechRecognizer(final Context context) {
2122a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi        return createSpeechRecognizer(context, null);
21379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    }
21479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
21579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    /**
2162a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Factory method to create a new {@code SpeechRecognizer}. Please note that
2171168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called before dispatching any
2182a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * command to the created {@code SpeechRecognizer}, otherwise no notifications will be
2191168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * received.
2201168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
22179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     * Use this version of the method to specify a specific service to direct this
2222a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link SpeechRecognizer} to. Normally you would not use this; use
2232a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link #createSpeechRecognizer(Context)} instead to use the system default recognition
2241168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * service.
22579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     *
2262a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context in which to create {@code SpeechRecognizer}
22779375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     * @param serviceComponent the {@link ComponentName} of a specific service to direct this
2282a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     *        {@code SpeechRecognizer} to
2292a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @return a new {@code SpeechRecognizer}
23079375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     */
2312a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    public static SpeechRecognizer createSpeechRecognizer(final Context context,
23279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            final ComponentName serviceComponent) {
2333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (context == null) {
2343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new IllegalArgumentException("Context cannot be null)");
23579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2372a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi        return new SpeechRecognizer(context, serviceComponent);
23879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
23979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
24079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
2413da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Sets the listener that will receive all the callbacks. The previous unfinished commands will
2423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * be executed with the old listener, while any following command will be executed with the new
2433da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * listener.
2443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *
2453da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * @param listener listener that will receive all the callbacks from the created
2462a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     *        {@link SpeechRecognizer}, this must not be null.
24779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
2483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void setRecognitionListener(RecognitionListener listener) {
2493da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2503da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
25179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
25279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
25379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
2543da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Starts listening for speech. Please note that
2551168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
2561168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
2571168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
25879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * @param recognizerIntent contains parameters for the recognition to be performed. The intent
2593da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *        may also contain optional extras, see {@link RecognizerIntent}. If these values are
2603da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *        not set explicitly, default values will be used by the recognizer.
26179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
2623da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void startListening(final Intent recognizerIntent) {
26379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (recognizerIntent == null) {
2643da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new IllegalArgumentException("intent must not be null");
26579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2663da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2673da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (mConnection == null) { // first time connection
2683da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mConnection = new Connection();
2695d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
270cb0be8a530d6fefdb05f009980c029c4da14bf98Mike LeBeau            Intent serviceIntent = new Intent(RecognitionService.SERVICE_INTERFACE);
2715d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
27279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            if (mServiceComponent == null) {
27379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
27479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                        Settings.Secure.VOICE_RECOGNITION_SERVICE);
27579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
27679375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                if (TextUtils.isEmpty(serviceComponent)) {
27779375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    Log.e(TAG, "no selected voice recognition service");
27879375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    mListener.onError(ERROR_CLIENT);
27979375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    return;
28079375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                }
28179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
28279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
28379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            } else {
28479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                serviceIntent.setComponent(mServiceComponent);
2855d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau            }
2865d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
2875d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau            if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
2883da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                Log.e(TAG, "bind to recognition service failed");
2893da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mConnection = null;
2903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mService = null;
2913da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mListener.onError(ERROR_CLIENT);
2923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                return;
2933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
29479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2953da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent));
29679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
29779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
29879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
29979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * Stops listening for speech. Speech captured so far will be recognized as if the user had
30079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * stopped speaking at this point. Note that in the default case, this does not need to be
30179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * called, as the speech endpointer will automatically stop the recognizer listening when it
30279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * determines speech has completed. However, you can manipulate endpointer parameters directly
30379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * using the intent extras defined in {@link RecognizerIntent}, in which case you may sometimes
3043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * want to manually call this method to stop listening sooner. Please note that
3051168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
3061168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
30779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
30879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public void stopListening() {
3093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
3103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_STOP));
3113da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /**
3143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Cancels the speech recognition. Please note that
3151168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
3161168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
3173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     */
3183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void cancel() {
3193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
3203da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_CANCEL));
3213da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3223da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private static void checkIsCalledFromMainThread() {
3243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (Looper.myLooper() != Looper.getMainLooper()) {
3253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new RuntimeException(
3262a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi                    "SpeechRecognizer should be used only from the application's main thread");
3273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
3283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3293da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void putMessage(Message msg) {
33179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (mService == null) {
3323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mPendingTasks.offer(msg);
3333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        } else {
3343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mHandler.sendMessage(msg);
3353da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
3363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3373da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3383da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3393da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleStartListening(Intent recognizerIntent) {
3407a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3417a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3427a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
3433da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        try {
3443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.startListening(recognizerIntent, mListener);
3453da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            if (DBG) Log.d(TAG, "service start listening command succeded");
3463da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        } catch (final RemoteException e) {
3473da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Log.e(TAG, "startListening() failed", e);
3483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
34979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
3503da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3513da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3523da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3533da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleStopMessage() {
3547a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3557a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3567a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
35779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        try {
3583da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.stopListening(mListener);
35979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "service stop listening command succeded");
36079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        } catch (final RemoteException e) {
36179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            Log.e(TAG, "stopListening() failed", e);
3623da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
36379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
36479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
36579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
3663da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3673da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleCancelMessage() {
3687a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3697a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3707a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
37179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        try {
3723da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.cancel(mListener);
37379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "service cancel command succeded");
37479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        } catch (final RemoteException e) {
37579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            Log.e(TAG, "cancel() failed", e);
3763da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
37779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
37879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
3797a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov
3807a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov    private boolean checkOpenConnection() {
3817a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (mService != null) {
3827a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return true;
3837a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
3847a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        mListener.onError(ERROR_CLIENT);
3857a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        Log.e(TAG, "not connected to the recognition service");
3867a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        return false;
3877a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov    }
38879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
3893da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** changes the listener */
3903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleChangeListener(RecognitionListener listener) {
3913da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener);
3923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mListener.mInternalListener = listener;
3933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3943da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
39579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
3962a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Destroys the {@code SpeechRecognizer} object.
39779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
39879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public void destroy() {
39979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (mConnection != null) {
40079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mContext.unbindService(mConnection);
40179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
4023da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mPendingTasks.clear();
40379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        mService = null;
4043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mConnection = null;
4051c3cca0abed55516d2c67f2f11fc888a6a66f341Valentin Kravtsov        mListener.mInternalListener = null;
40679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
40779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
40879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
4093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Internal wrapper of IRecognitionListener which will propagate the results to
4103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * RecognitionListener
41179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
4123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private class InternalListener extends IRecognitionListener.Stub {
4133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private RecognitionListener mInternalListener;
4143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
4153da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_BEGINNING_OF_SPEECH = 1;
4163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_BUFFER_RECEIVED = 2;
4173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_END_OF_SPEECH = 3;
4183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_ERROR = 4;
4193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_READY_FOR_SPEECH = 5;
4203da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_RESULTS = 6;
4213da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_PARTIAL_RESULTS = 7;
4223da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_RMS_CHANGED = 8;
4233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_ON_EVENT = 9;
4243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
4253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final Handler mInternalHandler = new Handler() {
4263da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            @Override
4273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            public void handleMessage(Message msg) {
4283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                if (mInternalListener == null) {
4293da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    return;
4303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                }
4313da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                switch (msg.what) {
4323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_BEGINNING_OF_SPEECH:
4333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onBeginningOfSpeech();
4343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4353da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_BUFFER_RECEIVED:
4363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onBufferReceived((byte[]) msg.obj);
4373da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4383da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_END_OF_SPEECH:
4393da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onEndOfSpeech();
4403da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4413da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_ERROR:
4423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onError((Integer) msg.obj);
4433da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_READY_FOR_SPEECH:
4453da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onReadyForSpeech((Bundle) msg.obj);
4463da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4473da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_RESULTS:
4483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onResults((Bundle) msg.obj);
4493da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4503da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_PARTIAL_RESULTS:
4513da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onPartialResults((Bundle) msg.obj);
4523da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4533da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_RMS_CHANGED:
4543da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onRmsChanged((Float) msg.obj);
4553da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4563da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_ON_EVENT:
4573da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj);
4583da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4593da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                }
4603da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
4613da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        };
46279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
46379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onBeginningOfSpeech() {
4643da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_BEGINNING_OF_SPEECH).sendToTarget();
46579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
46679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
46779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onBufferReceived(final byte[] buffer) {
4683da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_BUFFER_RECEIVED, buffer).sendToTarget();
46979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
47079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
47179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onEndOfSpeech() {
4723da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_END_OF_SPEECH).sendToTarget();
47379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
47479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
47579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onError(final int error) {
4763da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_ERROR, error).sendToTarget();
47779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
47879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
47979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onReadyForSpeech(final Bundle noiseParams) {
4803da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_READY_FOR_SPEECH, noiseParams).sendToTarget();
48179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
48279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
48379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onResults(final Bundle results) {
4843da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_RESULTS, results).sendToTarget();
48579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
48679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
48779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onPartialResults(final Bundle results) {
4883da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_PARTIAL_RESULTS, results).sendToTarget();
48979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
49079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
49179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onRmsChanged(final float rmsdB) {
4923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget();
4933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
4943da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
4953da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void onEvent(final int eventType, final Bundle params) {
4963da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
4973da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    .sendToTarget();
49879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
49979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
50079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov}
501