Home | History | Annotate | Download | only in scoaudiotest
      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 
     89     public ScoAudioTest() {
     90         Log.e(TAG, "contructor");
     91     }
     92 
     93     /** Called when the activity is first created. */
     94     @Override
     95     public void onCreate(Bundle icicle) {
     96         super.onCreate(icicle);
     97 
     98         setContentView(R.layout.scoaudiotest);
     99 
    100         mScoStateTxt = (TextView) findViewById(R.id.scoStateTxt);
    101         mVdStateTxt = (TextView) 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 = (TextView) 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 = (EditText) 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 = (Spinner) 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
    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
    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
    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 = (CheckBox) findViewById(R.id.useSecondAudioManager);
    212                 if (box.isChecked()) {
    213                     Log.i(TAG, "Using 2nd audio manager");
    214                     mngr = mAudioManager2;
    215                 }
    216                 box = (CheckBox) 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 
    276         SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, String fileName) {
    277             mContext = context;
    278             mPlayPauseButtonId = playPausebuttonId;
    279             mStopButtonId = stopButtonId;
    280             mFileNameBase = fileName;
    281             mPlayPauseButton = (ImageButton) findViewById(playPausebuttonId);
    282             ImageButton stop = (ImageButton) findViewById(stopButtonId);
    283 
    284             mPlayPauseButton.setOnClickListener(this);
    285             mPlayPauseButton.requestFocus();
    286             if (stop != null) {
    287                 stop.setOnClickListener(this);
    288             }
    289         }
    290 
    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 = (ImageButton) findViewById(playPausebuttonId);
    298             ImageButton stop = (ImageButton) findViewById(stopButtonId);
    299 
    300             mPlayPauseButton.setOnClickListener(this);
    301             mPlayPauseButton.requestFocus();
    302             if (stop != null) {
    303                 stop.setOnClickListener(this);
    304             }
    305         }
    306 
    307         @Override
    308         public void onClick(View v) {
    309             if (v.getId() == mPlayPauseButtonId) {
    310                 playOrPause();
    311             } else if (v.getId() == mStopButtonId) {
    312                 stop();
    313             }
    314         }
    315 
    316         public void playOrPause() {
    317         }
    318 
    319         public void stop() {
    320         }
    321 
    322         public boolean isPlaying() {
    323             return false;
    324         }
    325 
    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;
    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 
    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
    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
    403         public void stop() {
    404             if (mMediaPlayer != null) {
    405                 mMediaPlayer.stop();
    406                 mMediaPlayer.release();
    407                 mMediaPlayer = null;
    408             }
    409             updatePlayPauseButton();
    410         }
    411 
    412         @Override
    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;
    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
    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 
    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
    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
    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
    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 
    540         public MyUtteranceCompletedListener(String expectedUtteranceId) {
    541             mExpectedUtterance = expectedUtteranceId;
    542         }
    543 
    544         @Override
    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
    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