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
423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov * invoked only from the main application thread. Please note that the application must have
433da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov * {@link android.Manifest.permission#RECORD_AUDIO} permission to use this class.
4479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov */
452a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivipublic class SpeechRecognizer {
4679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** DEBUG value to enable verbose debug prints */
4779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    private final static boolean DBG = false;
4879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
4979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Log messages identifier */
502a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    private static final String TAG = "SpeechRecognizer";
5179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
5279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
5379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * Used to retrieve an {@code ArrayList<String>} from the {@link Bundle} passed to the
5479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * {@link RecognitionListener#onResults(Bundle)} and
5579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * {@link RecognitionListener#onPartialResults(Bundle)} methods. These strings are the possible
5679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * recognition results, where the first element is the most likely candidate.
5779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
583da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final String RESULTS_RECOGNITION = "results_recognition";
5979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
6079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Network operation timed out. */
613da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NETWORK_TIMEOUT = 1;
6279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
6379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Other network related errors. */
643da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NETWORK = 2;
6579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
6679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Audio recording error. */
673da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_AUDIO = 3;
6879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
6979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Server sends error status. */
703da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_SERVER = 4;
7179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
7279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** Other client side errors. */
733da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_CLIENT = 5;
7479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
7579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** No speech input */
763da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_SPEECH_TIMEOUT = 6;
7779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
7879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** No recognition result matched. */
793da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_NO_MATCH = 7;
8079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
8179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /** RecognitionService busy. */
823da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_RECOGNIZER_BUSY = 8;
833da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
843da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Insufficient permissions */
853da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public static final int ERROR_INSUFFICIENT_PERMISSIONS = 9;
863da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
873da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** action codes */
883da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_START = 1;
893da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_STOP = 2;
903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_CANCEL = 3;
913da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final static int MSG_CHANGE_LISTENER = 4;
923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The actual RecognitionService endpoint */
943da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private IRecognitionService mService;
953da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
963da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The connection to the actual service */
973da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private Connection mConnection;
983da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
993da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Context with which the manager was created */
1003da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final Context mContext;
10179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
10279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    /** Component to direct service intent to */
10379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    private final ComponentName mServiceComponent;
1043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1053da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** Handler that will execute the main tasks */
1063da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private Handler mHandler = new Handler() {
1073da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        @Override
1083da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void handleMessage(Message msg) {
1093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            switch (msg.what) {
1103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_START:
1113da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleStartListening((Intent) msg.obj);
1123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_STOP:
1143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleStopMessage();
1153da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_CANCEL:
1173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleCancelMessage();
1183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                case MSG_CHANGE_LISTENER:
1203da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    handleChangeListener((RecognitionListener) msg.obj);
1213da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    break;
1223da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
1233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
1243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    };
12579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
12679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Temporary queue, saving the messages until the connection will be established, afterwards,
1283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * only mHandler will receive the messages
12979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
1303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final Queue<Message> mPendingTasks = new LinkedList<Message>();
1313da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
1323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** The Listener that will receive all the callbacks */
1333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private final InternalListener mListener = new InternalListener();
13479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
13579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1362a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * The right way to create a {@code SpeechRecognizer} is by using
1372a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link #createSpeechRecognizer} static factory method
13879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
1392a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    private SpeechRecognizer(final Context context, final ComponentName serviceComponent) {
14079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        mContext = context;
14179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau        mServiceComponent = serviceComponent;
14279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
14379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
14479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1453da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Basic ServiceConnection that records the mService variable. Additionally, on creation it
1463da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * invokes the {@link IRecognitionService#startListening(Intent, IRecognitionListener)}.
14779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
14879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    private class Connection implements ServiceConnection {
14979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
1503da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void onServiceConnected(final ComponentName name, final IBinder service) {
1513da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            // always done on the application main thread, so no need to send message to mHandler
15279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mService = IRecognitionService.Stub.asInterface(service);
15379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "onServiceConnected - Success");
1543da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            while (!mPendingTasks.isEmpty()) {
1553da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mHandler.sendMessage(mPendingTasks.poll());
1563da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
15779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
15879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
15979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onServiceDisconnected(final ComponentName name) {
1603da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            // always done on the application main thread, so no need to send message to mHandler
16179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mService = null;
16279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mConnection = null;
1633da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mPendingTasks.clear();
16479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "onServiceDisconnected - Success");
16579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
16679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
16779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
16879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
16979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * Checks whether a speech recognition service is available on the system. If this method
1702a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * returns {@code false}, {@link SpeechRecognizer#createSpeechRecognizer(Context)} will
1713da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * fail.
17279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     *
1732a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context with which {@code SpeechRecognizer} will be created
17479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * @return {@code true} if recognition is available, {@code false} otherwise
17579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
17679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public static boolean isRecognitionAvailable(final Context context) {
17779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        final List<ResolveInfo> list = context.getPackageManager().queryIntentServices(
178cccd63c8e8e989a55cbeeb6c7d253a709139c223Valentin Kravtsov                new Intent(RecognitionService.SERVICE_INTERFACE), 0);
17979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        return list != null && list.size() != 0;
18079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
18179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
18279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
1832a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Factory method to create a new {@code SpeechRecognizer}. Please note that
1841168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called before dispatching any
1852a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * command to the created {@code SpeechRecognizer}, otherwise no notifications will be
1861168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * received.
1871168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
1882a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context in which to create {@code SpeechRecognizer}
1892a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @return a new {@code SpeechRecognizer}
19079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
1912a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    public static SpeechRecognizer createSpeechRecognizer(final Context context) {
1922a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi        return createSpeechRecognizer(context, null);
19379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    }
19479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
19579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau    /**
1962a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Factory method to create a new {@code SpeechRecognizer}. Please note that
1971168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called before dispatching any
1982a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * command to the created {@code SpeechRecognizer}, otherwise no notifications will be
1991168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * received.
2001168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
20179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     * Use this version of the method to specify a specific service to direct this
2022a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link SpeechRecognizer} to. Normally you would not use this; use
2032a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * {@link #createSpeechRecognizer(Context)} instead to use the system default recognition
2041168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * service.
20579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     *
2062a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @param context in which to create {@code SpeechRecognizer}
20779375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     * @param serviceComponent the {@link ComponentName} of a specific service to direct this
2082a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     *        {@code SpeechRecognizer} to
2092a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * @return a new {@code SpeechRecognizer}
21079375f761922b208e2e50ff13a63552c9d01567bMike LeBeau     */
2112a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi    public static SpeechRecognizer createSpeechRecognizer(final Context context,
21279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            final ComponentName serviceComponent) {
2133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (context == null) {
2143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new IllegalArgumentException("Context cannot be null)");
21579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2172a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi        return new SpeechRecognizer(context, serviceComponent);
21879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
21979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
22079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
2213da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Sets the listener that will receive all the callbacks. The previous unfinished commands will
2223da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * be executed with the old listener, while any following command will be executed with the new
2233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * listener.
2243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *
2253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * @param listener listener that will receive all the callbacks from the created
2262a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     *        {@link SpeechRecognizer}, this must not be null.
22779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
2283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void setRecognitionListener(RecognitionListener listener) {
2293da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_CHANGE_LISTENER, listener));
23179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
23279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
23379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
2343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Starts listening for speech. Please note that
2351168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
2361168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
2371168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     *
23879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * @param recognizerIntent contains parameters for the recognition to be performed. The intent
2393da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *        may also contain optional extras, see {@link RecognizerIntent}. If these values are
2403da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     *        not set explicitly, default values will be used by the recognizer.
24179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
2423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void startListening(final Intent recognizerIntent) {
24379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (recognizerIntent == null) {
2443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new IllegalArgumentException("intent must not be null");
24579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2463da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2473da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (mConnection == null) { // first time connection
2483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mConnection = new Connection();
2495d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
250cb0be8a530d6fefdb05f009980c029c4da14bf98Mike LeBeau            Intent serviceIntent = new Intent(RecognitionService.SERVICE_INTERFACE);
2515d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
25279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            if (mServiceComponent == null) {
25379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                String serviceComponent = Settings.Secure.getString(mContext.getContentResolver(),
25479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                        Settings.Secure.VOICE_RECOGNITION_SERVICE);
25579375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
25679375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                if (TextUtils.isEmpty(serviceComponent)) {
25779375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    Log.e(TAG, "no selected voice recognition service");
25879375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    mListener.onError(ERROR_CLIENT);
25979375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                    return;
26079375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                }
26179375f761922b208e2e50ff13a63552c9d01567bMike LeBeau
26279375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                serviceIntent.setComponent(ComponentName.unflattenFromString(serviceComponent));
26379375f761922b208e2e50ff13a63552c9d01567bMike LeBeau            } else {
26479375f761922b208e2e50ff13a63552c9d01567bMike LeBeau                serviceIntent.setComponent(mServiceComponent);
2655d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau            }
2665d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau
2675d34e9b63d5305934dcedac11e8dd658ae23c174Mike LeBeau            if (!mContext.bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE)) {
2683da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                Log.e(TAG, "bind to recognition service failed");
2693da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mConnection = null;
2703da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mService = null;
2713da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                mListener.onError(ERROR_CLIENT);
2723da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                return;
2733da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
27479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
2753da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_START, recognizerIntent));
27679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
27779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
27879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
27979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * Stops listening for speech. Speech captured so far will be recognized as if the user had
28079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * stopped speaking at this point. Note that in the default case, this does not need to be
28179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * called, as the speech endpointer will automatically stop the recognizer listening when it
28279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * determines speech has completed. However, you can manipulate endpointer parameters directly
28379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     * using the intent extras defined in {@link RecognizerIntent}, in which case you may sometimes
2843da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * want to manually call this method to stop listening sooner. Please note that
2851168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
2861168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
28779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
28879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public void stopListening() {
2893da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
2903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_STOP));
2913da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
2923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
2933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /**
2943da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Cancels the speech recognition. Please note that
2951168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * {@link #setRecognitionListener(RecognitionListener)} should be called beforehand, otherwise
2961168622bce0a8ab51362daadf4a22ea43dd46c10Valentin Kravtsov     * no notifications will be received.
2973da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     */
2983da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    public void cancel() {
2993da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        checkIsCalledFromMainThread();
3003da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        putMessage(Message.obtain(mHandler, MSG_CANCEL));
3013da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3023da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3033da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private static void checkIsCalledFromMainThread() {
3043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (Looper.myLooper() != Looper.getMainLooper()) {
3053da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            throw new RuntimeException(
3062a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi                    "SpeechRecognizer should be used only from the application's main thread");
3073da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
3083da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void putMessage(Message msg) {
31179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (mService == null) {
3123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mPendingTasks.offer(msg);
3133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        } else {
3143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mHandler.sendMessage(msg);
3153da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
3163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleStartListening(Intent recognizerIntent) {
3207a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3217a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3227a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
3233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        try {
3243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.startListening(recognizerIntent, mListener);
3253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            if (DBG) Log.d(TAG, "service start listening command succeded");
3263da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        } catch (final RemoteException e) {
3273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Log.e(TAG, "startListening() failed", e);
3283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
32979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
3303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3313da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleStopMessage() {
3347a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3357a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3367a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
33779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        try {
3383da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.stopListening(mListener);
33979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "service stop listening command succeded");
34079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        } catch (final RemoteException e) {
34179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            Log.e(TAG, "stopListening() failed", e);
3423da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
34379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
34479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
34579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
3463da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** sends the actual message to the service */
3473da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleCancelMessage() {
3487a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (!checkOpenConnection()) {
3497a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return;
3507a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
35179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        try {
3523da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mService.cancel(mListener);
35379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            if (DBG) Log.d(TAG, "service cancel command succeded");
35479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        } catch (final RemoteException e) {
35579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            Log.e(TAG, "cancel() failed", e);
3563da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            mListener.onError(ERROR_CLIENT);
35779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
35879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
3597a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov
3607a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov    private boolean checkOpenConnection() {
3617a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        if (mService != null) {
3627a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov            return true;
3637a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        }
3647a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        mListener.onError(ERROR_CLIENT);
3657a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        Log.e(TAG, "not connected to the recognition service");
3667a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov        return false;
3677a3c9d31bbc57f76d18d465eca605f28dc206f00Valentin Kravtsov    }
36879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
3693da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    /** changes the listener */
3703da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private void handleChangeListener(RecognitionListener listener) {
3713da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        if (DBG) Log.d(TAG, "handleChangeListener, listener=" + listener);
3723da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mListener.mInternalListener = listener;
3733da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    }
3743da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
37579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
3762a5d9f9b577376768372837723f0f42098aba13bJean-Michel Trivi     * Destroys the {@code SpeechRecognizer} object.
37779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
37879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    public void destroy() {
37979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        if (mConnection != null) {
38079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov            mContext.unbindService(mConnection);
38179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
3823da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mPendingTasks.clear();
38379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        mService = null;
3843da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        mConnection = null;
3851c3cca0abed55516d2c67f2f11fc888a6a66f341Valentin Kravtsov        mListener.mInternalListener = null;
38679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
38779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
38879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    /**
3893da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * Internal wrapper of IRecognitionListener which will propagate the results to
3903da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov     * RecognitionListener
39179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov     */
3923da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov    private class InternalListener extends IRecognitionListener.Stub {
3933da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private RecognitionListener mInternalListener;
3943da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
3953da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_BEGINNING_OF_SPEECH = 1;
3963da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_BUFFER_RECEIVED = 2;
3973da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_END_OF_SPEECH = 3;
3983da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_ERROR = 4;
3993da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_READY_FOR_SPEECH = 5;
4003da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_RESULTS = 6;
4013da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_PARTIAL_RESULTS = 7;
4023da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_RMS_CHANGED = 8;
4033da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final static int MSG_ON_EVENT = 9;
4043da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
4053da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        private final Handler mInternalHandler = new Handler() {
4063da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            @Override
4073da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            public void handleMessage(Message msg) {
4083da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                if (mInternalListener == null) {
4093da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    return;
4103da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                }
4113da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                switch (msg.what) {
4123da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_BEGINNING_OF_SPEECH:
4133da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onBeginningOfSpeech();
4143da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4153da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_BUFFER_RECEIVED:
4163da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onBufferReceived((byte[]) msg.obj);
4173da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4183da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_END_OF_SPEECH:
4193da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onEndOfSpeech();
4203da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4213da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_ERROR:
4223da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onError((Integer) msg.obj);
4233da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4243da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_READY_FOR_SPEECH:
4253da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onReadyForSpeech((Bundle) msg.obj);
4263da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4273da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_RESULTS:
4283da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onResults((Bundle) msg.obj);
4293da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4303da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_PARTIAL_RESULTS:
4313da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onPartialResults((Bundle) msg.obj);
4323da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4333da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_RMS_CHANGED:
4343da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onRmsChanged((Float) msg.obj);
4353da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4363da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    case MSG_ON_EVENT:
4373da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        mInternalListener.onEvent(msg.arg1, (Bundle) msg.obj);
4383da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                        break;
4393da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                }
4403da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            }
4413da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        };
44279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
44379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onBeginningOfSpeech() {
4443da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_BEGINNING_OF_SPEECH).sendToTarget();
44579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
44679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
44779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onBufferReceived(final byte[] buffer) {
4483da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_BUFFER_RECEIVED, buffer).sendToTarget();
44979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
45079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
45179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onEndOfSpeech() {
4523da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_END_OF_SPEECH).sendToTarget();
45379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
45479896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
45579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onError(final int error) {
4563da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_ERROR, error).sendToTarget();
45779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
45879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
45979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onReadyForSpeech(final Bundle noiseParams) {
4603da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_READY_FOR_SPEECH, noiseParams).sendToTarget();
46179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
46279896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
46379896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onResults(final Bundle results) {
4643da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_RESULTS, results).sendToTarget();
46579896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
46679896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
46779896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onPartialResults(final Bundle results) {
4683da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_PARTIAL_RESULTS, results).sendToTarget();
46979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
47079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov
47179896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        public void onRmsChanged(final float rmsdB) {
4723da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_RMS_CHANGED, rmsdB).sendToTarget();
4733da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        }
4743da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov
4753da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov        public void onEvent(final int eventType, final Bundle params) {
4763da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov            Message.obtain(mInternalHandler, MSG_ON_EVENT, eventType, eventType, params)
4773da3cad97269d694a6153771fb4a0c3775ca6ab5Valentin Kravtsov                    .sendToTarget();
47879896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov        }
47979896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov    }
48079896bd123aa3bc69c6455d4e2ddf2b2b555e6e5Valentin Kravtsov}
481