VoiceDialerActivity.java revision ef5d3e8cd31873c7af4902986ae61b408d0343bb
1538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project/*
2538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project *
4538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * you may not use this file except in compliance with the License.
6538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * You may obtain a copy of the License at
7538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project *
8538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project *
10538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * See the License for the specific language governing permissions and
14538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * limitations under the License.
15538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project */
16538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
17538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectpackage com.android.voicedialer;
18538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
19538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.app.Activity;
20538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.app.AlertDialog;
214a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdonimport android.app.Dialog;
22538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.content.Intent;
23538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.content.DialogInterface;
24538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.media.ToneGenerator;
25538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.media.AudioManager;
26538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.os.Bundle;
27538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.os.Handler;
28538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.os.SystemProperties;
29538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.os.Vibrator;
30538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.util.Config;
31538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.util.Log;
32538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.view.View;
33538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.widget.TextView;
34538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport android.widget.Toast;
35538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectimport java.io.File;
361b715dc663bd7155d996576774e487d31bf331f7Martin Hibdonimport java.io.InputStream;
37d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdonimport java.io.IOException;
38538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
39538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project/**
407a55150b308ed03d41091e4c3ac693d6eb0ab145mah * TODO: get rid of the anonymous classes
415f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon * TODO: merge with BluetoothVoiceDialerActivity
427a55150b308ed03d41091e4c3ac693d6eb0ab145mah *
43538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * This class is the user interface of the VoiceDialer application.
44538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * Its life cycle is as follows:
45538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <ul>
46538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The user presses the recognize key, and the VoiceDialerActivity starts.
47538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>A {@link RecognizerEngine} instance is created.
48538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The RecognizerEngine signals the user to speak with the Vibrator.
49538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The RecognizerEngine captures, processes, and recognizes speech
50538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * against the names in the contact list.
51538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The RecognizerEngine calls onRecognizerSuccess with a list of
52538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * sentences and corresponding Intents.
53538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>If the list is one element long, the corresponding Intent is dispatched.
54538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>Else an {@link AlertDialog} containing the list of sentences is
55538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * displayed.
56538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The user selects the desired sentence from the list,
57538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * and the corresponding Intent is dispatched.
58538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <ul>
59538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * Notes:
60538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <ul>
61538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * <li>The RecognizerEngine is kept and reused for the next recognition cycle.
62538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project * </ul>
63538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project */
64538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Projectpublic class VoiceDialerActivity extends Activity {
65538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
66538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private static final String TAG = "VoiceDialerActivity";
67538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
68538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private static final String MICROPHONE_EXTRA = "microphone";
69538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private static final String CONTACTS_EXTRA = "contacts";
705f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    private static final String SAMPLE_RATE_EXTRA = "samplerate";
714a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private static final String INTENTS_KEY = "intents";
72632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
73538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private static final int FAIL_PAUSE_MSEC = 5000;
7464c64e7c25e6efe31fa53369ec49db442b68ff9amah    private static final int SAMPLE_RATE = 11025;
75538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
764a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private static final int DIALOG_ID = 1;
774a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
785f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    private final static CommandRecognizerEngine mCommandEngine =
795f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon            new CommandRecognizerEngine();
8064c64e7c25e6efe31fa53369ec49db442b68ff9amah    private CommandRecognizerClient mCommandClient;
81538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private VoiceDialerTester mVoiceDialerTester;
82538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private Handler mHandler;
83538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private Thread mRecognizerThread = null;
84538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private AudioManager mAudioManager;
85538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private ToneGenerator mToneGenerator;
864a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private AlertDialog mAlertDialog;
87538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
88538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    @Override
89538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    protected void onCreate(Bundle icicle) {
90ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        if (Config.LOGD) Log.d(TAG, "onCreate");
91538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        super.onCreate(icicle);
92538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mHandler = new Handler();
93538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
94ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        mToneGenerator = new ToneGenerator(AudioManager.STREAM_RING,
95ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon                ToneGenerator.MAX_VOLUME);
96ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon    }
97ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon
98ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon    protected void onStart() {
99ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        if (Config.LOGD) Log.d(TAG, "onStart "  + getIntent());
100ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        super.onStart();
1012abf40fd5f901da1b6168aa778cbf7e6713a1e9bMartin Hibdon        mAudioManager.requestAudioFocus(
1022abf40fd5f901da1b6168aa778cbf7e6713a1e9bMartin Hibdon                null, AudioManager.STREAM_MUSIC,
1032abf40fd5f901da1b6168aa778cbf7e6713a1e9bMartin Hibdon                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
104be1584eb7e59c391a45aa21fb5e65ada1aedae9aDave Sparks
10564c64e7c25e6efe31fa53369ec49db442b68ff9amah        mCommandEngine.setContactsFile(newFile(getArg(CONTACTS_EXTRA)));
10664c64e7c25e6efe31fa53369ec49db442b68ff9amah        mCommandClient = new CommandRecognizerClient();
1075f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        mCommandEngine.setMinimizeResults(false);
1085f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        mCommandEngine.setAllowOpenEntries(true);
10964c64e7c25e6efe31fa53369ec49db442b68ff9amah
110538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // open main window
111538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        setTheme(android.R.style.Theme_Dialog);
112538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        setTitle(R.string.title);
113538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        setContentView(R.layout.voice_dialing);
114538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        findViewById(R.id.microphone_view).setVisibility(View.INVISIBLE);
115538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        findViewById(R.id.retry_view).setVisibility(View.INVISIBLE);
116538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        findViewById(R.id.microphone_loading_view).setVisibility(View.VISIBLE);
117538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (RecognizerLogger.isEnabled(this)) {
118538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            ((TextView)findViewById(R.id.substate)).setText(R.string.logging_enabled);
119538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
120632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
121538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // start the tester, if present
122538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mVoiceDialerTester = null;
123538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        File micDir = newFile(getArg(MICROPHONE_EXTRA));
124538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (micDir != null && micDir.isDirectory()) {
125538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mVoiceDialerTester = new VoiceDialerTester(micDir);
126538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            startNextTest();
127538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            return;
128538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
129538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
1305f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        startWork();
131538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
132538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
133538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private void startWork() {
134cd84f92b28c4d6fc55b76bce50434dd858f0d7d2Dave Sparks        // start the engine
135538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mRecognizerThread = new Thread() {
136538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            public void run() {
137538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                if (Config.LOGD) Log.d(TAG, "onCreate.Runnable.run");
1385f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                String sampleRateStr = getArg(SAMPLE_RATE_EXTRA);
1395f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                int sampleRate = SAMPLE_RATE;
1405f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                if (sampleRateStr != null) {
1415f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                    sampleRate = Integer.parseInt(sampleRateStr);
1425f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                }
14364c64e7c25e6efe31fa53369ec49db442b68ff9amah                mCommandEngine.recognize(mCommandClient, VoiceDialerActivity.this,
144538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                        newFile(getArg(MICROPHONE_EXTRA)),
1455f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon                        sampleRate);
146538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            }
147538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        };
148538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mRecognizerThread.start();
149538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
150632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
151538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private String getArg(String name) {
152538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (name == null) return null;
153538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        String arg = getIntent().getStringExtra(name);
154538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (arg != null) return arg;
155538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        arg = SystemProperties.get("app.voicedialer." + name);
156538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        return arg != null && arg.length() > 0 ? arg : null;
157538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
158632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
159538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private static File newFile(String name) {
160538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        return name != null ? new File(name) : null;
161538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
162632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
163538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private void startNextTest() {
164538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mHandler.postDelayed(new Runnable() {
165538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            public void run() {
166538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                if (mVoiceDialerTester == null) {
167538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    return;
168538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                }
169538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                if (!mVoiceDialerTester.stepToNextTest()) {
170538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    mVoiceDialerTester.report();
171538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    notifyText("Test completed!");
172538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    finish();
173538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    return;
174538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                }
175538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                File microphone = mVoiceDialerTester.getWavFile();
176538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                File contacts = newFile(getArg(CONTACTS_EXTRA));
1775f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon
178538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                notifyText("Testing\n" + microphone + "\n" + contacts);
17964c64e7c25e6efe31fa53369ec49db442b68ff9amah                mCommandEngine.recognize(mCommandClient, VoiceDialerActivity.this,
18064c64e7c25e6efe31fa53369ec49db442b68ff9amah                        microphone, SAMPLE_RATE);
181538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            }
182538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }, 2000);
183538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
184632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
185538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private int playSound(int toneType) {
186538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        int msecDelay = 1;
187632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
188538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // use the MediaPlayer to prompt the user
189538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (mToneGenerator != null) {
190538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mToneGenerator.startTone(toneType);
191538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            msecDelay = StrictMath.max(msecDelay, 300);
192538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
193538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
194538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // use the Vibrator to prompt the user
1951b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon        if ((mAudioManager != null) &&
1961b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon                (mAudioManager.shouldVibrate(AudioManager.VIBRATE_TYPE_RINGER))) {
197538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            final int VIBRATOR_TIME = 150;
198538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            final int VIBRATOR_GUARD_TIME = 150;
199538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            Vibrator vibrator = new Vibrator();
200538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            vibrator.vibrate(VIBRATOR_TIME);
201538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            msecDelay = StrictMath.max(msecDelay,
202538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    VIBRATOR_TIME + VIBRATOR_GUARD_TIME);
203538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
204632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
205538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        return msecDelay;
206538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
207632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
208538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    @Override
2095f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon    protected void onStop() {
2105f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        if (Config.LOGD) Log.d(TAG, "onStop");
211632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
2122abf40fd5f901da1b6168aa778cbf7e6713a1e9bMartin Hibdon        mAudioManager.abandonAudioFocus(null);
2132abf40fd5f901da1b6168aa778cbf7e6713a1e9bMartin Hibdon
214538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // no more tester
215538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mVoiceDialerTester = null;
216632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
217538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // shut down recognizer and wait for the thread to complete
218538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (mRecognizerThread !=  null) {
219538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mRecognizerThread.interrupt();
220538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            try {
221538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                mRecognizerThread.join();
222538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            } catch (InterruptedException e) {
2234a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (Config.LOGD) Log.d(TAG, "onStop mRecognizerThread.join exception " + e);
224538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            }
225538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mRecognizerThread = null;
226538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
227632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
228538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // clean up UI
229538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mHandler.removeCallbacks(mMicFlasher);
230538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        mHandler.removeMessages(0);
231632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
232538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        // clean up ToneGenerator
233538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        if (mToneGenerator != null) {
234538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mToneGenerator.release();
235538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mToneGenerator = null;
236538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
237632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
2385f25619fecb3fda9b34f90eb1e333a89ec431583Martin Hibdon        super.onStop();
239ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon
240ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        // It makes no sense to have this activity maintain state when in
241ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        // background.  When it stops, it should just be destroyed.
242ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        finish();
243538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
244632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
245538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private void notifyText(final CharSequence msg) {
246538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        Toast.makeText(VoiceDialerActivity.this, msg, Toast.LENGTH_SHORT).show();
247538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
248538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
249538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    private Runnable mMicFlasher = new Runnable() {
250538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        int visible = View.VISIBLE;
251538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
252538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        public void run() {
253538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            findViewById(R.id.microphone_view).setVisibility(visible);
254538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            findViewById(R.id.state).setVisibility(visible);
255538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            visible = visible == View.VISIBLE ? View.INVISIBLE : View.VISIBLE;
256538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project            mHandler.postDelayed(this, 750);
257538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        }
258538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    };
259538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
2604a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2614a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    protected Dialog onCreateDialog(int id, Bundle args) {
2624a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        final Intent intents[] = (Intent[])args.getParcelableArray(INTENTS_KEY);
2634a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2644a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        DialogInterface.OnClickListener clickListener =
2654a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            new DialogInterface.OnClickListener() {
2664a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2674a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            public void onClick(DialogInterface dialog, int which) {
2684a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (Config.LOGD) Log.d(TAG, "clickListener.onClick " + which);
2694a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                startActivityHelp(intents[which]);
2704a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                dismissDialog(DIALOG_ID);
2714a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mAlertDialog = null;
2724a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                finish();
2734a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            }
2744a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2754a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        };
2764a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2774a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        DialogInterface.OnCancelListener cancelListener =
2784a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            new DialogInterface.OnCancelListener() {
2794a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2804a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            public void onCancel(DialogInterface dialog) {
2814a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (Config.LOGD) Log.d(TAG, "cancelListener.onCancel");
2824a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                dismissDialog(DIALOG_ID);
2834a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mAlertDialog = null;
2844a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                finish();
2854a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            }
2864a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2874a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        };
2884a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2894a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        DialogInterface.OnClickListener positiveListener =
2904a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            new DialogInterface.OnClickListener() {
2914a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
2924a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            public void onClick(DialogInterface dialog, int which) {
2934a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (Config.LOGD) Log.d(TAG, "positiveListener.onClick " + which);
2944a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (intents.length == 1 && which == -1) which = 0;
2954a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                startActivityHelp(intents[which]);
2964a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                dismissDialog(DIALOG_ID);
2974a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mAlertDialog = null;
2984a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                finish();
2994a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            }
3004a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3014a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        };
3024a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3034a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        DialogInterface.OnClickListener negativeListener =
3044a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            new DialogInterface.OnClickListener() {
3054a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3064a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            public void onClick(DialogInterface dialog, int which) {
3074a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                if (Config.LOGD) Log.d(TAG, "negativeListener.onClick " + which);
3084a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                dismissDialog(DIALOG_ID);
3094a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                mAlertDialog = null;
3104a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                finish();
3114a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            }
3124a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3134a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        };
3144a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3154a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        String[] sentences = new String[intents.length];
3164a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        for (int i = 0; i < intents.length; i++) {
3174a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            sentences[i] = intents[i].getStringExtra(
3184a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    RecognizerEngine.SENTENCE_EXTRA);
3194a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        }
3204a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3214a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        mAlertDialog = intents.length > 1 ?
3224a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                new AlertDialog.Builder(VoiceDialerActivity.this)
3234a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setTitle(R.string.title)
3244a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setItems(sentences, clickListener)
3254a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setOnCancelListener(cancelListener)
3264a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setNegativeButton(android.R.string.cancel, negativeListener)
3274a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .show()
3284a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                :
3294a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                new AlertDialog.Builder(VoiceDialerActivity.this)
3304a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setTitle(R.string.title)
3314a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setItems(sentences, clickListener)
3324a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setOnCancelListener(cancelListener)
3334a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setPositiveButton(android.R.string.ok, positiveListener)
3344a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .setNegativeButton(android.R.string.cancel, negativeListener)
3354a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                .show();
3364a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
3374a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        return mAlertDialog;
3384a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    }
3394a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
34064c64e7c25e6efe31fa53369ec49db442b68ff9amah    private class CommandRecognizerClient implements RecognizerClient {
341d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        static final int MIN_VOLUME_TO_SKIP = 2;
34264c64e7c25e6efe31fa53369ec49db442b68ff9amah        /**
34364c64e7c25e6efe31fa53369ec49db442b68ff9amah         * Called by the {@link RecognizerEngine} when the microphone is started.
34464c64e7c25e6efe31fa53369ec49db442b68ff9amah         */
3451b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon        public void onMicrophoneStart(InputStream mic) {
34664c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Config.LOGD) Log.d(TAG, "onMicrophoneStart");
3471b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon            playSound(ToneGenerator.TONE_PROP_BEEP);
3481b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon
349d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int ringVolume = mAudioManager.getStreamVolume(
350d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    AudioManager.STREAM_RING);
351d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            Log.d(TAG, "ringVolume " + ringVolume);
352d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
353d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            if (ringVolume >= MIN_VOLUME_TO_SKIP) {
354d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                // now we're playing a sound, and corrupting the input sample.
355d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                // So we need to pull that junk off of the input stream so that the
356d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                // recognizer won't see it.
357d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                try {
358d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    skipBeep(mic);
359d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                } catch (java.io.IOException e) {
360d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    Log.e(TAG, "IOException " + e);
361d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                }
362d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            } else {
363d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                Log.d(TAG, "no tone");
3641b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon            }
365632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
36664c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (mVoiceDialerTester != null) return;
367632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
36864c64e7c25e6efe31fa53369ec49db442b68ff9amah            mHandler.post(new Runnable() {
36964c64e7c25e6efe31fa53369ec49db442b68ff9amah                public void run() {
37064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.microphone_loading_view).setVisibility(View.INVISIBLE);
37164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ((TextView)findViewById(R.id.state)).setText(R.string.listening);
37264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.post(mMicFlasher);
37364c64e7c25e6efe31fa53369ec49db442b68ff9amah                }
37464c64e7c25e6efe31fa53369ec49db442b68ff9amah            });
37564c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
376538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
377d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        /**
378d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon         *  Beep detection
379d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon         */
380d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int START_WINDOW_MS = 500;  // Beep detection window duration in ms
381d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int SINE_FREQ = 400;        // base sine frequency on beep
382d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int NUM_PERIODS_BLOCK = 10; // number of sine periods in one energy averaging block
383d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int THRESHOLD = 8;          // absolute pseudo energy threshold
384d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int START = 0;              // beep detection start
385d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int RISING = 1;             // beep rising edge start
386d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        private static final int TOP = 2;                // beep constant energy detected
387d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
388d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon        void skipBeep(InputStream is) throws IOException {
389d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int sampleCount = ((SAMPLE_RATE / SINE_FREQ) * NUM_PERIODS_BLOCK);
390d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int blockSize = 2 * sampleCount; // energy averaging block
391d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
392d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            if (is == null || blockSize == 0) {
393d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                return;
394d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            }
395d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
396d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            byte[] buf = new byte[blockSize];
397d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int maxBytes = 2 * ((START_WINDOW_MS * SAMPLE_RATE) / 1000);
398d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            maxBytes = ((maxBytes-1) / blockSize + 1) * blockSize;
399d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
400d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int count = 0;
401d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int state = START;  // detection state
402d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            long prevE = 0; // previous pseudo energy
403d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            long peak = 0;
404d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            int threshold =  THRESHOLD*sampleCount;  // absolute energy threshold
405d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            Log.d(TAG, "blockSize " + blockSize);
406d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
407d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            while (count < maxBytes) {
408d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                int cnt = 0;
409d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                while (cnt < blockSize) {
410d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    int n = is.read(buf, cnt, blockSize-cnt);
411d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    if (n < 0) {
412d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        throw new java.io.IOException();
413d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    }
414d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    cnt += n;
415d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                }
416d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
417d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                // compute pseudo energy
418d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                cnt = blockSize;
419d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                long sumx = 0;
420d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                long sumxx = 0;
421d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                while (cnt >= 2) {
422d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    short smp = (short)((buf[cnt - 1] << 8) + (buf[cnt - 2] & 0xFF));
423d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    sumx += smp;
424d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    sumxx += smp*smp;
425d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    cnt -= 2;
4261b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon                }
427d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                long energy = (sumxx*sampleCount - sumx*sumx)/(sampleCount*sampleCount);
428d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                Log.d(TAG, "sumx " + sumx + " sumxx " + sumxx + " ee " + energy);
429d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon
430d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                switch (state) {
431d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    case START:
432d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        if (energy > threshold && energy > (prevE * 2) && prevE != 0) {
433d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            // rising edge if energy doubled and > abs threshold
434d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            state = RISING;
435d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            if (Config.LOGD) Log.d(TAG, "start RISING: " + count +" time: "+ (((1000*count)/2)/SAMPLE_RATE));
436d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        }
437d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        break;
438d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    case RISING:
439d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        if (energy < threshold || energy < (prevE / 2)){
440d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            // energy fell back below half of previous, back to start
441d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            if (Config.LOGD) Log.d(TAG, "back to START: " + count +" time: "+ (((1000*count)/2)/SAMPLE_RATE));
442d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            peak = 0;
443d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            state = START;
444d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        } else if (energy > (prevE / 2) && energy < (prevE * 2)) {
445d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            // Start of constant energy
446d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            if (Config.LOGD) Log.d(TAG, "start TOP: " + count +" time: "+ (((1000*count)/2)/SAMPLE_RATE));
447d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            if (peak < energy) {
448d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                                peak = energy;
449d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            }
450d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            state = TOP;
451d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        }
452d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        break;
453d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    case TOP:
454d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        if (energy < threshold || energy < (peak / 2)) {
455d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            // e went to less than half of the peak
456d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            if (Config.LOGD) Log.d(TAG, "end TOP: " + count +" time: "+ (((1000*count)/2)/SAMPLE_RATE));
457d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                            return;
458d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        }
459d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                        break;
460d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                    }
461d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                prevE = energy;
462d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon                count += blockSize;
4631b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon            }
464d23e5f670b10a582761421d8bc101d4a2d660ac0Martin Hibdon            if (Config.LOGD) Log.d(TAG, "no beep detected, timed out");
4651b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon        }
4661b715dc663bd7155d996576774e487d31bf331f7Martin Hibdon
46764c64e7c25e6efe31fa53369ec49db442b68ff9amah        /**
46864c64e7c25e6efe31fa53369ec49db442b68ff9amah         * Called by the {@link RecognizerEngine} if the recognizer fails.
46964c64e7c25e6efe31fa53369ec49db442b68ff9amah         */
47064c64e7c25e6efe31fa53369ec49db442b68ff9amah        public void onRecognitionFailure(final String msg) {
47164c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Config.LOGD) Log.d(TAG, "onRecognitionFailure " + msg);
47264c64e7c25e6efe31fa53369ec49db442b68ff9amah
47364c64e7c25e6efe31fa53369ec49db442b68ff9amah            // get work off UAPI thread
47464c64e7c25e6efe31fa53369ec49db442b68ff9amah            mHandler.post(new Runnable() {
47564c64e7c25e6efe31fa53369ec49db442b68ff9amah                public void run() {
47664c64e7c25e6efe31fa53369ec49db442b68ff9amah                    // failure, so beep about it
47764c64e7c25e6efe31fa53369ec49db442b68ff9amah                    playSound(ToneGenerator.TONE_PROP_NACK);
47864c64e7c25e6efe31fa53369ec49db442b68ff9amah
47964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.removeCallbacks(mMicFlasher);
48064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ((TextView)findViewById(R.id.state)).setText(R.string.please_try_again);
48164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.state).setVisibility(View.VISIBLE);
48264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.microphone_view).setVisibility(View.INVISIBLE);
48364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.retry_view).setVisibility(View.VISIBLE);
48464c64e7c25e6efe31fa53369ec49db442b68ff9amah
48564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (mVoiceDialerTester != null) {
48664c64e7c25e6efe31fa53369ec49db442b68ff9amah                        mVoiceDialerTester.onRecognitionFailure(msg);
48764c64e7c25e6efe31fa53369ec49db442b68ff9amah                        startNextTest();
48864c64e7c25e6efe31fa53369ec49db442b68ff9amah                        return;
48964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }
490538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
49164c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.postDelayed(new Runnable() {
49264c64e7c25e6efe31fa53369ec49db442b68ff9amah                        public void run() {
49364c64e7c25e6efe31fa53369ec49db442b68ff9amah                            finish();
49464c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }
49564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }, FAIL_PAUSE_MSEC);
496538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                }
49764c64e7c25e6efe31fa53369ec49db442b68ff9amah            });
49864c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
499538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
50064c64e7c25e6efe31fa53369ec49db442b68ff9amah        /**
50164c64e7c25e6efe31fa53369ec49db442b68ff9amah         * Called by the {@link RecognizerEngine} on an internal error.
50264c64e7c25e6efe31fa53369ec49db442b68ff9amah         */
50364c64e7c25e6efe31fa53369ec49db442b68ff9amah        public void onRecognitionError(final String msg) {
50464c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Config.LOGD) Log.d(TAG, "onRecognitionError " + msg);
50564c64e7c25e6efe31fa53369ec49db442b68ff9amah
50664c64e7c25e6efe31fa53369ec49db442b68ff9amah            // get work off UAPI thread
50764c64e7c25e6efe31fa53369ec49db442b68ff9amah            mHandler.post(new Runnable() {
50864c64e7c25e6efe31fa53369ec49db442b68ff9amah                public void run() {
50964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    // error, so beep about it
51064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    playSound(ToneGenerator.TONE_PROP_NACK);
51164c64e7c25e6efe31fa53369ec49db442b68ff9amah
51264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.removeCallbacks(mMicFlasher);
51364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ((TextView)findViewById(R.id.state)).setText(R.string.please_try_again);
51464c64e7c25e6efe31fa53369ec49db442b68ff9amah                    ((TextView)findViewById(R.id.substate)).setText(R.string.recognition_error);
51564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.state).setVisibility(View.VISIBLE);
51664c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.microphone_view).setVisibility(View.INVISIBLE);
51764c64e7c25e6efe31fa53369ec49db442b68ff9amah                    findViewById(R.id.retry_view).setVisibility(View.VISIBLE);
51864c64e7c25e6efe31fa53369ec49db442b68ff9amah
51964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (mVoiceDialerTester != null) {
52064c64e7c25e6efe31fa53369ec49db442b68ff9amah                        mVoiceDialerTester.onRecognitionError(msg);
52164c64e7c25e6efe31fa53369ec49db442b68ff9amah                        startNextTest();
52264c64e7c25e6efe31fa53369ec49db442b68ff9amah                        return;
523538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    }
524632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
52564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.postDelayed(new Runnable() {
52664c64e7c25e6efe31fa53369ec49db442b68ff9amah                        public void run() {
52764c64e7c25e6efe31fa53369ec49db442b68ff9amah                            finish();
52864c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }
52964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    }, FAIL_PAUSE_MSEC);
530538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                }
53164c64e7c25e6efe31fa53369ec49db442b68ff9amah            });
53264c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
533538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project
53464c64e7c25e6efe31fa53369ec49db442b68ff9amah        /**
53564c64e7c25e6efe31fa53369ec49db442b68ff9amah         * Called by the {@link RecognizerEngine} when is succeeds.  If there is
53664c64e7c25e6efe31fa53369ec49db442b68ff9amah         * only one item, then the Intent is dispatched immediately.
53764c64e7c25e6efe31fa53369ec49db442b68ff9amah         * If there are more, then an AlertDialog is displayed and the user is
53864c64e7c25e6efe31fa53369ec49db442b68ff9amah         * prompted to select.
53964c64e7c25e6efe31fa53369ec49db442b68ff9amah         * @param intents a list of Intents corresponding to the sentences.
54064c64e7c25e6efe31fa53369ec49db442b68ff9amah         */
54164c64e7c25e6efe31fa53369ec49db442b68ff9amah        public void onRecognitionSuccess(final Intent[] intents) {
54264c64e7c25e6efe31fa53369ec49db442b68ff9amah            if (Config.LOGD) Log.d(TAG, "onRecognitionSuccess " + intents.length);
5434a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // repackage our intents as a bundle so that we can pass it into
5444a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // showDialog.  This in required so that we can handle it when
5454a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            // orientation changes and the activity is destroyed and recreated.
5464a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            final Bundle args = new Bundle();
5474a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            args.putParcelableArray(INTENTS_KEY, intents);
54864c64e7c25e6efe31fa53369ec49db442b68ff9amah
54964c64e7c25e6efe31fa53369ec49db442b68ff9amah            mHandler.post(new Runnable() {
55064c64e7c25e6efe31fa53369ec49db442b68ff9amah
55164c64e7c25e6efe31fa53369ec49db442b68ff9amah                public void run() {
55264c64e7c25e6efe31fa53369ec49db442b68ff9amah                    // success, so beep about it
55364c64e7c25e6efe31fa53369ec49db442b68ff9amah                    playSound(ToneGenerator.TONE_PROP_ACK);
55464c64e7c25e6efe31fa53369ec49db442b68ff9amah
55564c64e7c25e6efe31fa53369ec49db442b68ff9amah                    mHandler.removeCallbacks(mMicFlasher);
55664c64e7c25e6efe31fa53369ec49db442b68ff9amah
5574a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    showDialog(DIALOG_ID, args);
55864c64e7c25e6efe31fa53369ec49db442b68ff9amah
55964c64e7c25e6efe31fa53369ec49db442b68ff9amah                    // start the next test
56064c64e7c25e6efe31fa53369ec49db442b68ff9amah                    if (mVoiceDialerTester != null) {
56164c64e7c25e6efe31fa53369ec49db442b68ff9amah                        mVoiceDialerTester.onRecognitionSuccess(intents);
56264c64e7c25e6efe31fa53369ec49db442b68ff9amah                        startNextTest();
56364c64e7c25e6efe31fa53369ec49db442b68ff9amah                        mHandler.postDelayed(new Runnable() {
56464c64e7c25e6efe31fa53369ec49db442b68ff9amah                            public void run() {
5654a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                                dismissDialog(DIALOG_ID);
5664a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                                mAlertDialog = null;
56764c64e7c25e6efe31fa53369ec49db442b68ff9amah                            }
56864c64e7c25e6efe31fa53369ec49db442b68ff9amah                        }, 2000);
569538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                    }
570538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project                }
57164c64e7c25e6efe31fa53369ec49db442b68ff9amah            });
57264c64e7c25e6efe31fa53369ec49db442b68ff9amah        }
573538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
574632bb9327078cbe2794ff24be8bb28e4f81309f1The Android Open Source Project
5754a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    // post a Toast if not real contacts or microphone
5764a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    private void startActivityHelp(Intent intent) {
5774a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        if (getArg(MICROPHONE_EXTRA) == null &&
5784a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                getArg(CONTACTS_EXTRA) == null) {
5794a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            startActivity(intent);
5804a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        } else {
5814a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon            notifyText(intent.
5824a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    getStringExtra(RecognizerEngine.SENTENCE_EXTRA) +
5834a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon                    "\n" + intent.toString());
5844a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon        }
5854a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon
5864a330957ce5190ed86c57e0c65910359b866cba7Martin Hibdon    }
587538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    @Override
588538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    protected void onDestroy() {
589ef5d3e8cd31873c7af4902986ae61b408d0343bbMartin Hibdon        if (Config.LOGD) Log.d(TAG, "onDestroy");
590538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project        super.onDestroy();
591538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project    }
592538879a6f24ff7305e66d719e751b5d612029bf3The Android Open Source Project}
593