1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.scoaudiotest;
18 
19 import android.app.Activity;
20 import android.bluetooth.BluetoothAdapter;
21 import android.bluetooth.BluetoothDevice;
22 import android.bluetooth.BluetoothHeadset;
23 import android.bluetooth.BluetoothProfile;
24 import android.content.BroadcastReceiver;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.IntentFilter;
28 import android.content.res.AssetFileDescriptor;
29 import android.media.AudioManager;
30 import android.media.MediaPlayer;
31 import android.media.MediaRecorder;
32 import android.os.Bundle;
33 import android.os.Environment;
34 import android.os.Handler;
35 import android.speech.tts.TextToSpeech;
36 import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
37 import android.util.Log;
38 import android.view.KeyEvent;
39 import android.view.View;
40 import android.view.View.OnClickListener;
41 import android.widget.ArrayAdapter;
42 import android.widget.CheckBox;
43 import android.widget.CompoundButton;
44 import android.widget.CompoundButton.OnCheckedChangeListener;
45 import android.widget.EditText;
46 import android.widget.ImageButton;
47 import android.widget.ImageView;
48 import android.widget.Spinner;
49 import android.widget.TextView;
50 import android.widget.ToggleButton;
51 
52 import java.io.File;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Locale;
56 
57 public class ScoAudioTest extends Activity {
58 
59     final static String TAG = "ScoAudioTest";
60 
61     AudioManager mAudioManager;
62     AudioManager mAudioManager2;
63     boolean mForceScoOn;
64     ToggleButton mScoButton;
65     ToggleButton mVoiceDialerButton;
66     boolean mVoiceDialerOn;
67     String mLastRecordedFile;
68     SimpleMediaController mMediaControllers[] = new SimpleMediaController[2];
69     private TextToSpeech mTts;
70     private HashMap<String, String> mTtsParams;
71     private int mOriginalVoiceVolume;
72     EditText mSpeakText;
73     boolean mTtsInited;
74     private Handler mHandler;
75     private static final String UTTERANCE = "utterance";
76     private static Intent sVoiceCommandIntent;
77     private File mSampleFile;
78     ToggleButton mTtsToFileButton;
79     private boolean mTtsToFile;
80     private int mCurrentMode;
81     Spinner mModeSpinner;
82     private BluetoothHeadset mBluetoothHeadset;
83     private BluetoothDevice mBluetoothHeadsetDevice;
84     TextView mScoStateTxt;
85     TextView mVdStateTxt;
86 
87     private final BroadcastReceiver mReceiver = new ScoBroadcastReceiver();
88 
ScoAudioTest()89     public ScoAudioTest() {
90         Log.e(TAG, "contructor");
91     }
92 
93     /** Called when the activity is first created. */
94     @Override
onCreate(Bundle icicle)95     public void onCreate(Bundle icicle) {
96         super.onCreate(icicle);
97 
98         setContentView(R.layout.scoaudiotest);
99 
100         mScoStateTxt = findViewById(R.id.scoStateTxt);
101         mVdStateTxt = findViewById(R.id.vdStateTxt);
102 
103         IntentFilter intentFilter =
104             new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
105         intentFilter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
106         intentFilter.addAction(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
107         registerReceiver(mReceiver, intentFilter);
108 
109         mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
110         mAudioManager2 = (AudioManager) getApplicationContext().getSystemService(Context.AUDIO_SERVICE);
111         mHandler = new Handler();
112 
113         mMediaControllers[0] = new SimplePlayerController(this, R.id.playPause1, R.id.stop1,
114                 R.raw.sine440_mo_16b_16k, AudioManager.STREAM_BLUETOOTH_SCO);
115         TextView name = findViewById(R.id.playPause1Text);
116         name.setText("VOICE_CALL stream");
117 
118         mScoButton = (ToggleButton)findViewById(R.id.ForceScoButton);
119         mScoButton.setOnCheckedChangeListener(mForceScoChanged);
120         mForceScoOn = false;
121         mScoButton.setChecked(mForceScoOn);
122 
123         mVoiceDialerButton = (ToggleButton)findViewById(R.id.VoiceDialerButton);
124         mVoiceDialerButton.setOnCheckedChangeListener(mVoiceDialerChanged);
125         mVoiceDialerOn = false;
126         mVoiceDialerButton.setChecked(mVoiceDialerOn);
127 
128 
129         mMediaControllers[1] = new SimpleRecordController(this, R.id.recStop1, 0, "Sco_record_");
130         mTtsInited = false;
131         mTts = new TextToSpeech(this, new TtsInitListener());
132         mTtsParams = new HashMap<String, String>();
133         mTtsParams.put(TextToSpeech.Engine.KEY_PARAM_STREAM,
134                 String.valueOf(AudioManager.STREAM_BLUETOOTH_SCO));
135         mTtsParams.put(TextToSpeech.Engine.KEY_PARAM_UTTERANCE_ID,
136                 UTTERANCE);
137 
138         mSpeakText = findViewById(R.id.speakTextEdit);
139         mSpeakText.setOnKeyListener(mSpeakKeyListener);
140         mSpeakText.setText("sco audio test sentence");
141         mTtsToFileButton = (ToggleButton)findViewById(R.id.TtsToFileButton);
142         mTtsToFileButton.setOnCheckedChangeListener(mTtsToFileChanged);
143         mTtsToFile = true;
144         mTtsToFileButton.setChecked(mTtsToFile);
145 
146         mModeSpinner = findViewById(R.id.modeSpinner);
147         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
148                 android.R.layout.simple_spinner_item, mModeStrings);
149         adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
150         mModeSpinner.setAdapter(adapter);
151         mModeSpinner.setOnItemSelectedListener(mModeChanged);
152         mCurrentMode = mAudioManager.getMode();
153         mModeSpinner.setSelection(mCurrentMode);
154 
155         mBluetoothHeadsetDevice = null;
156         BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
157         if (btAdapter != null) {
158             btAdapter.getProfileProxy(this, mBluetoothProfileServiceListener,
159                                     BluetoothProfile.HEADSET);
160         }
161 
162         sVoiceCommandIntent = new Intent(Intent.ACTION_VOICE_COMMAND);
163         sVoiceCommandIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
164     }
165 
166     @Override
onDestroy()167     public void onDestroy() {
168         super.onDestroy();
169         mTts.shutdown();
170         unregisterReceiver(mReceiver);
171         if (mBluetoothHeadset != null) {
172             BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
173             if (btAdapter != null) {
174                 btAdapter.closeProfileProxy(BluetoothProfile.HEADSET, mBluetoothHeadset);
175             }
176         }
177     }
178 
179     @Override
onPause()180     protected void onPause() {
181         super.onPause();
182 //        mForceScoOn = false;
183 //        mScoButton.setChecked(mForceScoOn);
184         mMediaControllers[0].stop();
185         mMediaControllers[1].stop();
186         mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
187                 mOriginalVoiceVolume, 0);
188     }
189 
190     @Override
onResume()191     protected void onResume() {
192         super.onResume();
193         mLastRecordedFile = "";
194         mMediaControllers[0].mFileName = "";
195         mOriginalVoiceVolume = mAudioManager.getStreamVolume(
196                 AudioManager.STREAM_BLUETOOTH_SCO);
197         setVolumeControlStream(AudioManager.STREAM_BLUETOOTH_SCO);
198         mCurrentMode = mAudioManager.getMode();
199         mModeSpinner.setSelection(mCurrentMode);
200     }
201 
202     private OnCheckedChangeListener mForceScoChanged
203     = new OnCheckedChangeListener(){
204         @Override
205         public void onCheckedChanged(CompoundButton buttonView,
206                 boolean isChecked) {
207             if (mForceScoOn != isChecked) {
208                 mForceScoOn = isChecked;
209                 AudioManager mngr = mAudioManager;
210                 boolean useVirtualCall = false;
211                 CheckBox box = findViewById(R.id.useSecondAudioManager);
212                 if (box.isChecked()) {
213                     Log.i(TAG, "Using 2nd audio manager");
214                     mngr = mAudioManager2;
215                 }
216                 box = findViewById(R.id.useVirtualCallCheckBox);
217                 useVirtualCall = box.isChecked();
218 
219                 if (mForceScoOn) {
220                     if (useVirtualCall) {
221                         Log.e(TAG, "startBluetoothScoVirtualCall() IN");
222                         mngr.startBluetoothScoVirtualCall();
223                         Log.e(TAG, "startBluetoothScoVirtualCall() OUT");
224                     } else {
225                         Log.e(TAG, "startBluetoothSco() IN");
226                         mngr.startBluetoothSco();
227                         Log.e(TAG, "startBluetoothSco() OUT");
228                     }
229                 } else {
230                     Log.e(TAG, "stopBluetoothSco() IN");
231                     mngr.stopBluetoothSco();
232                     Log.e(TAG, "stopBluetoothSco() OUT");
233                 }
234             }
235         }
236     };
237 
238     private OnCheckedChangeListener mVoiceDialerChanged
239     = new OnCheckedChangeListener(){
240         @Override
241         public void onCheckedChanged(CompoundButton buttonView,
242                 boolean isChecked) {
243             if (mVoiceDialerOn != isChecked) {
244                 mVoiceDialerOn = isChecked;
245                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
246                     if (mVoiceDialerOn) {
247                         mBluetoothHeadset.startVoiceRecognition(mBluetoothHeadsetDevice);
248                     } else {
249                         mBluetoothHeadset.stopVoiceRecognition(mBluetoothHeadsetDevice);
250                     }
251                 }
252             }
253         }
254     };
255 
256     private OnCheckedChangeListener mTtsToFileChanged
257     = new OnCheckedChangeListener(){
258         @Override
259         public void onCheckedChanged(CompoundButton buttonView,
260                 boolean isChecked) {
261             mTtsToFile = isChecked;
262         }
263     };
264 
265     private class SimpleMediaController implements OnClickListener {
266         int mPlayPauseButtonId;
267         int mStopButtonId;
268         Context mContext;
269         ImageView mPlayPauseButton;
270         int mPlayImageResource;
271         int mPauseImageResource;
272         String mFileNameBase;
273         String mFileName;
274         int mFileResId;
275 
SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, String fileName)276         SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, String fileName) {
277             mContext = context;
278             mPlayPauseButtonId = playPausebuttonId;
279             mStopButtonId = stopButtonId;
280             mFileNameBase = fileName;
281             mPlayPauseButton = findViewById(playPausebuttonId);
282             ImageButton stop = findViewById(stopButtonId);
283 
284             mPlayPauseButton.setOnClickListener(this);
285             mPlayPauseButton.requestFocus();
286             if (stop != null) {
287                 stop.setOnClickListener(this);
288             }
289         }
290 
SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, int fileResId)291         SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, int fileResId) {
292             mContext = context;
293             mPlayPauseButtonId = playPausebuttonId;
294             mStopButtonId = stopButtonId;
295             mFileNameBase = "";
296             mFileResId = fileResId;
297             mPlayPauseButton = findViewById(playPausebuttonId);
298             ImageButton stop = findViewById(stopButtonId);
299 
300             mPlayPauseButton.setOnClickListener(this);
301             mPlayPauseButton.requestFocus();
302             if (stop != null) {
303                 stop.setOnClickListener(this);
304             }
305         }
306 
307         @Override
onClick(View v)308         public void onClick(View v) {
309             if (v.getId() == mPlayPauseButtonId) {
310                 playOrPause();
311             } else if (v.getId() == mStopButtonId) {
312                 stop();
313             }
314         }
315 
playOrPause()316         public void playOrPause() {
317         }
318 
stop()319         public void stop() {
320         }
321 
isPlaying()322         public boolean isPlaying() {
323             return false;
324         }
325 
updatePlayPauseButton()326         public void updatePlayPauseButton() {
327             mPlayPauseButton.setImageResource(isPlaying() ? mPauseImageResource : mPlayImageResource);
328         }
329     }
330 
331     private class SimplePlayerController extends SimpleMediaController {
332         private MediaPlayer mMediaPlayer;
333         private int mStreamType;
SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, String fileName, int stream)334         SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, String fileName, int stream) {
335             super(context, playPausebuttonId, stopButtonId, fileName);
336 
337             mPlayImageResource = android.R.drawable.ic_media_play;
338             mPauseImageResource = android.R.drawable.ic_media_pause;
339             mStreamType = stream;
340             mFileName = Environment.getExternalStorageDirectory().toString() + "/music/" +
341                         mFileNameBase + "_" + ".wav";
342         }
343 
SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, int fileResId, int stream)344         SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, int fileResId, int stream) {
345             super(context, playPausebuttonId, stopButtonId, fileResId);
346 
347             mPlayImageResource = android.R.drawable.ic_media_play;
348             mPauseImageResource = android.R.drawable.ic_media_pause;
349             mStreamType = stream;
350             mFileName = "";
351         }
352 
353         @Override
playOrPause()354         public void playOrPause() {
355             Log.e(TAG, "playOrPause playing: "+((mMediaPlayer == null)?false:!mMediaPlayer.isPlaying())+
356                     " mMediaPlayer: "+mMediaPlayer+
357                     " mFileName: "+mFileName+
358                     " mLastRecordedFile: "+mLastRecordedFile);
359             if (mMediaPlayer == null || !mMediaPlayer.isPlaying()){
360                 if (mMediaPlayer == null) {
361                     if (mFileName != mLastRecordedFile) {
362                         mFileName = mLastRecordedFile;
363                         Log.e(TAG, "new recorded file: "+mFileName);
364                     }
365                     try {
366                         mMediaPlayer = new MediaPlayer();
367                         if (mFileName.equals("")) {
368                             Log.e(TAG, "Playing from resource");
369                             AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(mFileResId);
370                             mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
371                             afd.close();
372                         } else {
373                             Log.e(TAG, "Playing file: "+mFileName);
374                             mMediaPlayer.setDataSource(mFileName);
375                         }
376                         mMediaPlayer.setAudioStreamType(mStreamType);
377                         mMediaPlayer.prepare();
378                         mMediaPlayer.setLooping(true);
379                     } catch (Exception ex) {
380                         Log.e(TAG, "mMediaPlayercreate failed:", ex);
381                         mMediaPlayer.release();
382                         mMediaPlayer = null;
383                     }
384 
385                     if (mMediaPlayer != null) {
386                         mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
387                             @Override
388                             public void onCompletion(MediaPlayer mp) {
389                                 updatePlayPauseButton();
390                             }
391                         });
392                     }
393                 }
394                 if (mMediaPlayer != null) {
395                     mMediaPlayer.start();
396                 }
397             } else {
398                 mMediaPlayer.pause();
399             }
400             updatePlayPauseButton();
401         }
402         @Override
stop()403         public void stop() {
404             if (mMediaPlayer != null) {
405                 mMediaPlayer.stop();
406                 mMediaPlayer.release();
407                 mMediaPlayer = null;
408             }
409             updatePlayPauseButton();
410         }
411 
412         @Override
isPlaying()413         public boolean isPlaying() {
414             if (mMediaPlayer != null) {
415                 return mMediaPlayer.isPlaying();
416             } else {
417                 return false;
418             }
419         }
420     }
421 
422     private class SimpleRecordController extends SimpleMediaController {
423         private MediaRecorder mMediaRecorder;
424         private int mFileCount = 0;
425         private int mState = 0;
SimpleRecordController(Context context, int playPausebuttonId, int stopButtonId, String fileName)426         SimpleRecordController(Context context, int playPausebuttonId, int stopButtonId, String fileName) {
427             super(context, playPausebuttonId, stopButtonId, fileName);
428             Log.e(TAG, "SimpleRecordController cstor");
429             mPlayImageResource = R.drawable.record;
430             mPauseImageResource = R.drawable.stop;
431         }
432 
433         @Override
playOrPause()434         public void playOrPause() {
435             if (mState == 0) {
436                 setup();
437                 try {
438                     mMediaRecorder.start();
439                     mState = 1;
440                 } catch (Exception e) {
441                     Log.e(TAG, "Could start MediaRecorder: ", e);
442                     mMediaRecorder.release();
443                     mMediaRecorder = null;
444                     mState = 0;
445                 }
446             } else {
447                 try {
448                     mMediaRecorder.stop();
449                     mMediaRecorder.reset();
450                 } catch (Exception e) {
451                     Log.e(TAG, "Could not stop MediaRecorder: ", e);
452                     mMediaRecorder.release();
453                     mMediaRecorder = null;
454                 } finally {
455                     mState = 0;
456                 }
457             }
458             updatePlayPauseButton();
459         }
460 
setup()461         public void setup() {
462             Log.e(TAG, "SimpleRecordController setup()");
463             if (mMediaRecorder == null) {
464                 mMediaRecorder = new MediaRecorder();
465             }
466             mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
467             mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
468             mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
469             mFileName = Environment.getExternalStorageDirectory().toString() + "/music/" +
470                         mFileNameBase + "_" + ++mFileCount + ".amr";
471             mLastRecordedFile = mFileName;
472             Log.e(TAG, "recording to file: "+mLastRecordedFile);
473             mMediaRecorder.setOutputFile(mFileName);
474             try {
475                 mMediaRecorder.prepare();
476             }
477             catch (Exception e) {
478                 Log.e(TAG, "Could not prepare MediaRecorder: ", e);
479                 mMediaRecorder.release();
480                 mMediaRecorder = null;
481             }
482         }
483 
484         @Override
stop()485         public void stop() {
486             if (mMediaRecorder != null) {
487                 try {
488                     mMediaRecorder.stop();
489                 } catch (Exception e) {
490                     Log.e(TAG, "Could not stop MediaRecorder: ", e);
491                 } finally {
492                     mMediaRecorder.release();
493                     mMediaRecorder = null;
494                 }
495             }
496             updatePlayPauseButton();
497         }
498 
499         @Override
isPlaying()500         public boolean isPlaying() {
501             if (mState == 1) {
502                 return true;
503             } else {
504                 return false;
505             }
506         }
507     }
508 
509     class TtsInitListener implements TextToSpeech.OnInitListener {
510         @Override
onInit(int status)511         public void onInit(int status) {
512             // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR.
513             Log.e(TAG, "onInit for tts");
514             if (status != TextToSpeech.SUCCESS) {
515                 // Initialization failed.
516                 Log.e(TAG, "Could not initialize TextToSpeech.");
517                 return;
518             }
519 
520             if (mTts == null) {
521                 Log.e(TAG, "null tts");
522                 return;
523             }
524 
525             int result = mTts.setLanguage(Locale.US);
526             if (result == TextToSpeech.LANG_MISSING_DATA ||
527                 result == TextToSpeech.LANG_NOT_SUPPORTED) {
528                // Lanuage data is missing or the language is not supported.
529                 Log.e(TAG, "Language is not available.");
530                 return;
531             }
532             mTts.setOnUtteranceCompletedListener(new MyUtteranceCompletedListener(UTTERANCE));
533             mTtsInited = true;
534          }
535     }
536 
537     class MyUtteranceCompletedListener implements OnUtteranceCompletedListener {
538         private final String mExpectedUtterance;
539 
MyUtteranceCompletedListener(String expectedUtteranceId)540         public MyUtteranceCompletedListener(String expectedUtteranceId) {
541             mExpectedUtterance = expectedUtteranceId;
542         }
543 
544         @Override
onUtteranceCompleted(String utteranceId)545         public void onUtteranceCompleted(String utteranceId) {
546             Log.e(TAG, "onUtteranceCompleted " + utteranceId);
547             if (mTtsToFile) {
548                 if (mSampleFile != null && mSampleFile.exists()) {
549                     MediaPlayer mediaPlayer = new MediaPlayer();
550                     try {
551                         mediaPlayer.setDataSource(mSampleFile.getPath());
552                         mediaPlayer.setAudioStreamType(AudioManager.STREAM_BLUETOOTH_SCO);
553                         mediaPlayer.prepare();
554                     } catch (Exception ex) {
555                         Log.e(TAG, "mMediaPlayercreate failed:", ex);
556                         mediaPlayer.release();
557                         mediaPlayer = null;
558                     }
559 
560                     if (mediaPlayer != null) {
561                         mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
562                             @Override
563                             public void onCompletion(MediaPlayer mp) {
564                                 mp.release();
565                                 if (mSampleFile != null && mSampleFile.exists()) {
566                                     mSampleFile.delete();
567                                     mSampleFile = null;
568                                 }
569                               mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
570                               mOriginalVoiceVolume, 0);
571 //                              Debug.stopMethodTracing();
572                             }
573                         });
574                         mediaPlayer.start();
575                     }
576                 } else {
577                     Log.e(TAG, "synthesizeToFile did not create file");
578                 }
579             } else {
580                 mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
581                         mOriginalVoiceVolume, 0);
582 //                Debug.stopMethodTracing();
583             }
584 
585             Log.e(TAG, "end speak, volume: "+mOriginalVoiceVolume);
586         }
587     }
588 
589 
590     private View.OnKeyListener mSpeakKeyListener
591     = new View.OnKeyListener() {
592         @Override
593         public boolean onKey(View v, int keyCode, KeyEvent event) {
594             if (event.getAction() == KeyEvent.ACTION_DOWN) {
595                 switch (keyCode) {
596                     case KeyEvent.KEYCODE_DPAD_CENTER:
597                     case KeyEvent.KEYCODE_ENTER:
598                         if (!mTtsInited) {
599                             Log.e(TAG, "Tts not inited ");
600                             return false;
601                         }
602                         mOriginalVoiceVolume = mAudioManager.getStreamVolume(
603                                 AudioManager.STREAM_BLUETOOTH_SCO);
604                         Log.e(TAG, "start speak, volume: "+mOriginalVoiceVolume);
605                         mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
606                                 mOriginalVoiceVolume/2, 0);
607 
608                         // we now have SCO connection and TTS, so we can start.
609                         mHandler.post(new Runnable() {
610                             @Override
611                             public void run() {
612 //                                Debug.startMethodTracing("tts");
613 
614                                 if (mTtsToFile) {
615                                     if (mSampleFile != null && mSampleFile.exists()) {
616                                         mSampleFile.delete();
617                                         mSampleFile = null;
618                                     }
619                                     mSampleFile = new File(Environment.getExternalStorageDirectory(), "mytts.wav");
620                                     mTts.synthesizeToFile(mSpeakText.getText().toString(), mTtsParams, mSampleFile.getPath());
621                                 } else {
622                                     mTts.speak(mSpeakText.getText().toString(),
623                                         TextToSpeech.QUEUE_FLUSH,
624                                         mTtsParams);
625                                 }
626                             }
627                         });
628                         return true;
629                 }
630             }
631             return false;
632         }
633     };
634 
635     private static final String[] mModeStrings = {
636         "NORMAL", "RINGTONE", "IN_CALL", "IN_COMMUNICATION"
637     };
638 
639     private Spinner.OnItemSelectedListener mModeChanged
640         = new Spinner.OnItemSelectedListener() {
641         @Override
642         public void onItemSelected(android.widget.AdapterView av, View v,
643                     int position, long id) {
644             if (mCurrentMode != position) {
645                 mCurrentMode = position;
646                 mAudioManager.setMode(mCurrentMode);
647             }
648         }
649 
650         @Override
651         public void onNothingSelected(android.widget.AdapterView av) {
652         }
653     };
654 
655     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
656         new BluetoothProfile.ServiceListener() {
657         @Override
658         public void onServiceConnected(int profile, BluetoothProfile proxy) {
659             mBluetoothHeadset = (BluetoothHeadset) proxy;
660             List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
661             if (deviceList.size() > 0) {
662                 mBluetoothHeadsetDevice = deviceList.get(0);
663             } else {
664                 mBluetoothHeadsetDevice = null;
665             }
666         }
667         @Override
668         public void onServiceDisconnected(int profile) {
669             if (mBluetoothHeadset != null) {
670                 List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
671                 if (devices.size() == 0) {
672                     mBluetoothHeadsetDevice = null;
673                 }
674                 mBluetoothHeadset = null;
675             }
676         }
677     };
678 
679     private int mChangedState = -1;
680     private int mUpdatedState = -1;
681     private int mUpdatedPrevState = -1;
682 
683     private class ScoBroadcastReceiver extends BroadcastReceiver {
684         @Override
onReceive(Context context, Intent intent)685         public void onReceive(Context context, Intent intent) {
686             String action = intent.getAction();
687 
688             if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
689                 int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
690                 mVdStateTxt.setText(Integer.toString(state));
691                 Log.e(TAG, "BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED: "+state);
692             } else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)) {
693                 mChangedState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
694                 Log.e(TAG, "ACTION_SCO_AUDIO_STATE_CHANGED: "+mChangedState);
695                 mScoStateTxt.setText("changed: "+Integer.toString(mChangedState)+
696                         " updated: "+Integer.toString(mUpdatedState)+
697                         " prev updated: "+Integer.toString(mUpdatedPrevState));
698             } else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
699                 mUpdatedState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
700                 mUpdatedPrevState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, -1);
701                 Log.e(TAG, "ACTION_SCO_AUDIO_STATE_UPDATED, state: "+mUpdatedState+" prev state: "+mUpdatedPrevState);
702                 mScoStateTxt.setText("changed: "+Integer.toString(mChangedState)+
703                         " updated: "+Integer.toString(mUpdatedState)+
704                         " prev updated: "+Integer.toString(mUpdatedPrevState));
705                 if (mForceScoOn && mUpdatedState == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
706                     mForceScoOn = false;
707                     mScoButton.setChecked(mForceScoOn);
708                     mAudioManager.stopBluetoothSco();
709                 }
710             }
711         }
712     }
713 
714 }
715