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
17package com.android.scoaudiotest;
18
19import android.app.Activity;
20import android.bluetooth.BluetoothAdapter;
21import android.bluetooth.BluetoothDevice;
22import android.bluetooth.BluetoothHeadset;
23import android.bluetooth.BluetoothProfile;
24import android.content.BroadcastReceiver;
25import android.content.Context;
26import android.content.Intent;
27import android.content.IntentFilter;
28import android.content.res.AssetFileDescriptor;
29import android.media.AudioManager;
30import android.media.MediaPlayer;
31import android.media.MediaRecorder;
32import android.os.Bundle;
33import android.os.Environment;
34import android.os.Handler;
35import android.speech.tts.TextToSpeech;
36import android.speech.tts.TextToSpeech.OnUtteranceCompletedListener;
37import android.util.Log;
38import android.view.KeyEvent;
39import android.view.View;
40import android.view.View.OnClickListener;
41import android.widget.ArrayAdapter;
42import android.widget.CheckBox;
43import android.widget.CompoundButton;
44import android.widget.CompoundButton.OnCheckedChangeListener;
45import android.widget.EditText;
46import android.widget.ImageButton;
47import android.widget.ImageView;
48import android.widget.Spinner;
49import android.widget.TextView;
50import android.widget.ToggleButton;
51
52import java.io.File;
53import java.util.HashMap;
54import java.util.List;
55import java.util.Locale;
56
57public 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                CheckBox box = (CheckBox) findViewById(R.id.useSecondAudioManager);
211                if (box.isChecked()) {
212                    Log.i(TAG, "Using 2nd audio manager");
213                    mngr = mAudioManager2;
214                }
215
216                if (mForceScoOn) {
217                    Log.e(TAG, "startBluetoothSco() IN");
218                    mngr.startBluetoothSco();
219                    Log.e(TAG, "startBluetoothSco() OUT");
220                } else {
221                    Log.e(TAG, "stopBluetoothSco() IN");
222                    mngr.stopBluetoothSco();
223                    Log.e(TAG, "stopBluetoothSco() OUT");
224                }
225            }
226        }
227    };
228
229    private OnCheckedChangeListener mVoiceDialerChanged
230    = new OnCheckedChangeListener(){
231        @Override
232        public void onCheckedChanged(CompoundButton buttonView,
233                boolean isChecked) {
234            if (mVoiceDialerOn != isChecked) {
235                mVoiceDialerOn = isChecked;
236                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
237                    if (mVoiceDialerOn) {
238                        mBluetoothHeadset.startVoiceRecognition(mBluetoothHeadsetDevice);
239                    } else {
240                        mBluetoothHeadset.stopVoiceRecognition(mBluetoothHeadsetDevice);
241                    }
242                }
243            }
244        }
245    };
246
247    private OnCheckedChangeListener mTtsToFileChanged
248    = new OnCheckedChangeListener(){
249        @Override
250        public void onCheckedChanged(CompoundButton buttonView,
251                boolean isChecked) {
252            mTtsToFile = isChecked;
253        }
254    };
255
256    private class SimpleMediaController implements OnClickListener {
257        int mPlayPauseButtonId;
258        int mStopButtonId;
259        Context mContext;
260        ImageView mPlayPauseButton;
261        int mPlayImageResource;
262        int mPauseImageResource;
263        String mFileNameBase;
264        String mFileName;
265        int mFileResId;
266
267        SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, String fileName) {
268            mContext = context;
269            mPlayPauseButtonId = playPausebuttonId;
270            mStopButtonId = stopButtonId;
271            mFileNameBase = fileName;
272            mPlayPauseButton = (ImageButton) findViewById(playPausebuttonId);
273            ImageButton stop = (ImageButton) findViewById(stopButtonId);
274
275            mPlayPauseButton.setOnClickListener(this);
276            mPlayPauseButton.requestFocus();
277            if (stop != null) {
278                stop.setOnClickListener(this);
279            }
280        }
281
282        SimpleMediaController(Context context, int playPausebuttonId, int stopButtonId, int fileResId) {
283            mContext = context;
284            mPlayPauseButtonId = playPausebuttonId;
285            mStopButtonId = stopButtonId;
286            mFileNameBase = "";
287            mFileResId = fileResId;
288            mPlayPauseButton = (ImageButton) findViewById(playPausebuttonId);
289            ImageButton stop = (ImageButton) findViewById(stopButtonId);
290
291            mPlayPauseButton.setOnClickListener(this);
292            mPlayPauseButton.requestFocus();
293            if (stop != null) {
294                stop.setOnClickListener(this);
295            }
296        }
297
298        @Override
299        public void onClick(View v) {
300            if (v.getId() == mPlayPauseButtonId) {
301                playOrPause();
302            } else if (v.getId() == mStopButtonId) {
303                stop();
304            }
305        }
306
307        public void playOrPause() {
308        }
309
310        public void stop() {
311        }
312
313        public boolean isPlaying() {
314            return false;
315        }
316
317        public void updatePlayPauseButton() {
318            mPlayPauseButton.setImageResource(isPlaying() ? mPauseImageResource : mPlayImageResource);
319        }
320    }
321
322    private class SimplePlayerController extends SimpleMediaController {
323        private MediaPlayer mMediaPlayer;
324        private int mStreamType;
325        SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, String fileName, int stream) {
326            super(context, playPausebuttonId, stopButtonId, fileName);
327
328            mPlayImageResource = android.R.drawable.ic_media_play;
329            mPauseImageResource = android.R.drawable.ic_media_pause;
330            mStreamType = stream;
331            mFileName = Environment.getExternalStorageDirectory().toString() + "/music/" +
332                        mFileNameBase + "_" + ".wav";
333        }
334
335        SimplePlayerController(Context context, int playPausebuttonId, int stopButtonId, int fileResId, int stream) {
336            super(context, playPausebuttonId, stopButtonId, fileResId);
337
338            mPlayImageResource = android.R.drawable.ic_media_play;
339            mPauseImageResource = android.R.drawable.ic_media_pause;
340            mStreamType = stream;
341            mFileName = "";
342        }
343
344        @Override
345        public void playOrPause() {
346            Log.e(TAG, "playOrPause playing: "+((mMediaPlayer == null)?false:!mMediaPlayer.isPlaying())+
347                    " mMediaPlayer: "+mMediaPlayer+
348                    " mFileName: "+mFileName+
349                    " mLastRecordedFile: "+mLastRecordedFile);
350            if (mMediaPlayer == null || !mMediaPlayer.isPlaying()){
351                if (mMediaPlayer == null) {
352                    if (mFileName != mLastRecordedFile) {
353                        mFileName = mLastRecordedFile;
354                        Log.e(TAG, "new recorded file: "+mFileName);
355                    }
356                    try {
357                        mMediaPlayer = new MediaPlayer();
358                        if (mFileName.equals("")) {
359                            Log.e(TAG, "Playing from resource");
360                            AssetFileDescriptor afd = mContext.getResources().openRawResourceFd(mFileResId);
361                            mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
362                            afd.close();
363                        } else {
364                            Log.e(TAG, "Playing file: "+mFileName);
365                            mMediaPlayer.setDataSource(mFileName);
366                        }
367                        mMediaPlayer.setAudioStreamType(mStreamType);
368                        mMediaPlayer.prepare();
369                        mMediaPlayer.setLooping(true);
370                    } catch (Exception ex) {
371                        Log.e(TAG, "mMediaPlayercreate failed:", ex);
372                        mMediaPlayer.release();
373                        mMediaPlayer = null;
374                    }
375
376                    if (mMediaPlayer != null) {
377                        mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
378                            @Override
379                            public void onCompletion(MediaPlayer mp) {
380                                updatePlayPauseButton();
381                            }
382                        });
383                    }
384                }
385                if (mMediaPlayer != null) {
386                    mMediaPlayer.start();
387                }
388            } else {
389                mMediaPlayer.pause();
390            }
391            updatePlayPauseButton();
392        }
393        @Override
394        public void stop() {
395            if (mMediaPlayer != null) {
396                mMediaPlayer.stop();
397                mMediaPlayer.release();
398                mMediaPlayer = null;
399            }
400            updatePlayPauseButton();
401        }
402
403        @Override
404        public boolean isPlaying() {
405            if (mMediaPlayer != null) {
406                return mMediaPlayer.isPlaying();
407            } else {
408                return false;
409            }
410        }
411    }
412
413    private class SimpleRecordController extends SimpleMediaController {
414        private MediaRecorder mMediaRecorder;
415        private int mFileCount = 0;
416        private int mState = 0;
417        SimpleRecordController(Context context, int playPausebuttonId, int stopButtonId, String fileName) {
418            super(context, playPausebuttonId, stopButtonId, fileName);
419            Log.e(TAG, "SimpleRecordController cstor");
420            mPlayImageResource = R.drawable.record;
421            mPauseImageResource = R.drawable.stop;
422        }
423
424        @Override
425        public void playOrPause() {
426            if (mState == 0) {
427                setup();
428                try {
429                    mMediaRecorder.start();
430                    mState = 1;
431                } catch (Exception e) {
432                    Log.e(TAG, "Could start MediaRecorder: ", e);
433                    mMediaRecorder.release();
434                    mMediaRecorder = null;
435                    mState = 0;
436                }
437            } else {
438                try {
439                    mMediaRecorder.stop();
440                    mMediaRecorder.reset();
441                } catch (Exception e) {
442                    Log.e(TAG, "Could not stop MediaRecorder: ", e);
443                    mMediaRecorder.release();
444                    mMediaRecorder = null;
445                } finally {
446                    mState = 0;
447                }
448            }
449            updatePlayPauseButton();
450        }
451
452        public void setup() {
453            Log.e(TAG, "SimpleRecordController setup()");
454            if (mMediaRecorder == null) {
455                mMediaRecorder = new MediaRecorder();
456            }
457            mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
458            mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
459            mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
460            mFileName = Environment.getExternalStorageDirectory().toString() + "/music/" +
461                        mFileNameBase + "_" + ++mFileCount + ".amr";
462            mLastRecordedFile = mFileName;
463            Log.e(TAG, "recording to file: "+mLastRecordedFile);
464            mMediaRecorder.setOutputFile(mFileName);
465            try {
466                mMediaRecorder.prepare();
467            }
468            catch (Exception e) {
469                Log.e(TAG, "Could not prepare MediaRecorder: ", e);
470                mMediaRecorder.release();
471                mMediaRecorder = null;
472            }
473        }
474
475        @Override
476        public void stop() {
477            if (mMediaRecorder != null) {
478                try {
479                    mMediaRecorder.stop();
480                } catch (Exception e) {
481                    Log.e(TAG, "Could not stop MediaRecorder: ", e);
482                } finally {
483                    mMediaRecorder.release();
484                    mMediaRecorder = null;
485                }
486            }
487            updatePlayPauseButton();
488        }
489
490        @Override
491        public boolean isPlaying() {
492            if (mState == 1) {
493                return true;
494            } else {
495                return false;
496            }
497        }
498    }
499
500    class TtsInitListener implements TextToSpeech.OnInitListener {
501        @Override
502        public void onInit(int status) {
503            // status can be either TextToSpeech.SUCCESS or TextToSpeech.ERROR.
504            Log.e(TAG, "onInit for tts");
505            if (status != TextToSpeech.SUCCESS) {
506                // Initialization failed.
507                Log.e(TAG, "Could not initialize TextToSpeech.");
508                return;
509            }
510
511            if (mTts == null) {
512                Log.e(TAG, "null tts");
513                return;
514            }
515
516            int result = mTts.setLanguage(Locale.US);
517            if (result == TextToSpeech.LANG_MISSING_DATA ||
518                result == TextToSpeech.LANG_NOT_SUPPORTED) {
519               // Lanuage data is missing or the language is not supported.
520                Log.e(TAG, "Language is not available.");
521                return;
522            }
523            mTts.setOnUtteranceCompletedListener(new MyUtteranceCompletedListener(UTTERANCE));
524            mTtsInited = true;
525         }
526    }
527
528    class MyUtteranceCompletedListener implements OnUtteranceCompletedListener {
529        private final String mExpectedUtterance;
530
531        public MyUtteranceCompletedListener(String expectedUtteranceId) {
532            mExpectedUtterance = expectedUtteranceId;
533        }
534
535        @Override
536        public void onUtteranceCompleted(String utteranceId) {
537            Log.e(TAG, "onUtteranceCompleted " + utteranceId);
538            if (mTtsToFile) {
539                if (mSampleFile != null && mSampleFile.exists()) {
540                    MediaPlayer mediaPlayer = new MediaPlayer();
541                    try {
542                        mediaPlayer.setDataSource(mSampleFile.getPath());
543                        mediaPlayer.setAudioStreamType(AudioManager.STREAM_BLUETOOTH_SCO);
544                        mediaPlayer.prepare();
545                    } catch (Exception ex) {
546                        Log.e(TAG, "mMediaPlayercreate failed:", ex);
547                        mediaPlayer.release();
548                        mediaPlayer = null;
549                    }
550
551                    if (mediaPlayer != null) {
552                        mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
553                            @Override
554                            public void onCompletion(MediaPlayer mp) {
555                                mp.release();
556                                if (mSampleFile != null && mSampleFile.exists()) {
557                                    mSampleFile.delete();
558                                    mSampleFile = null;
559                                }
560                              mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
561                              mOriginalVoiceVolume, 0);
562//                              Debug.stopMethodTracing();
563                            }
564                        });
565                        mediaPlayer.start();
566                    }
567                } else {
568                    Log.e(TAG, "synthesizeToFile did not create file");
569                }
570            } else {
571                mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
572                        mOriginalVoiceVolume, 0);
573//                Debug.stopMethodTracing();
574            }
575
576            Log.e(TAG, "end speak, volume: "+mOriginalVoiceVolume);
577        }
578    }
579
580
581    private View.OnKeyListener mSpeakKeyListener
582    = new View.OnKeyListener() {
583        @Override
584        public boolean onKey(View v, int keyCode, KeyEvent event) {
585            if (event.getAction() == KeyEvent.ACTION_DOWN) {
586                switch (keyCode) {
587                    case KeyEvent.KEYCODE_DPAD_CENTER:
588                    case KeyEvent.KEYCODE_ENTER:
589                        if (!mTtsInited) {
590                            Log.e(TAG, "Tts not inited ");
591                            return false;
592                        }
593                        mOriginalVoiceVolume = mAudioManager.getStreamVolume(
594                                AudioManager.STREAM_BLUETOOTH_SCO);
595                        Log.e(TAG, "start speak, volume: "+mOriginalVoiceVolume);
596                        mAudioManager.setStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO,
597                                mOriginalVoiceVolume/2, 0);
598
599                        // we now have SCO connection and TTS, so we can start.
600                        mHandler.post(new Runnable() {
601                            @Override
602                            public void run() {
603//                                Debug.startMethodTracing("tts");
604
605                                if (mTtsToFile) {
606                                    if (mSampleFile != null && mSampleFile.exists()) {
607                                        mSampleFile.delete();
608                                        mSampleFile = null;
609                                    }
610                                    mSampleFile = new File(Environment.getExternalStorageDirectory(), "mytts.wav");
611                                    mTts.synthesizeToFile(mSpeakText.getText().toString(), mTtsParams, mSampleFile.getPath());
612                                } else {
613                                    mTts.speak(mSpeakText.getText().toString(),
614                                        TextToSpeech.QUEUE_FLUSH,
615                                        mTtsParams);
616                                }
617                            }
618                        });
619                        return true;
620                }
621            }
622            return false;
623        }
624    };
625
626    private static final String[] mModeStrings = {
627        "NORMAL", "RINGTONE", "IN_CALL", "IN_COMMUNICATION"
628    };
629
630    private Spinner.OnItemSelectedListener mModeChanged
631        = new Spinner.OnItemSelectedListener() {
632        @Override
633        public void onItemSelected(android.widget.AdapterView av, View v,
634                    int position, long id) {
635            if (mCurrentMode != position) {
636                mCurrentMode = position;
637                mAudioManager.setMode(mCurrentMode);
638            }
639        }
640
641        @Override
642        public void onNothingSelected(android.widget.AdapterView av) {
643        }
644    };
645
646    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
647        new BluetoothProfile.ServiceListener() {
648        @Override
649        public void onServiceConnected(int profile, BluetoothProfile proxy) {
650            mBluetoothHeadset = (BluetoothHeadset) proxy;
651            List<BluetoothDevice> deviceList = mBluetoothHeadset.getConnectedDevices();
652            if (deviceList.size() > 0) {
653                mBluetoothHeadsetDevice = deviceList.get(0);
654            } else {
655                mBluetoothHeadsetDevice = null;
656            }
657        }
658        @Override
659        public void onServiceDisconnected(int profile) {
660            if (mBluetoothHeadset != null) {
661                List<BluetoothDevice> devices = mBluetoothHeadset.getConnectedDevices();
662                if (devices.size() == 0) {
663                    mBluetoothHeadsetDevice = null;
664                }
665                mBluetoothHeadset = null;
666            }
667        }
668    };
669
670    private int mChangedState = -1;
671    private int mUpdatedState = -1;
672    private int mUpdatedPrevState = -1;
673
674    private class ScoBroadcastReceiver extends BroadcastReceiver {
675        @Override
676        public void onReceive(Context context, Intent intent) {
677            String action = intent.getAction();
678
679            if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
680                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
681                mVdStateTxt.setText(Integer.toString(state));
682                Log.e(TAG, "BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED: "+state);
683            } else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED)) {
684                mChangedState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
685                Log.e(TAG, "ACTION_SCO_AUDIO_STATE_CHANGED: "+mChangedState);
686                mScoStateTxt.setText("changed: "+Integer.toString(mChangedState)+
687                        " updated: "+Integer.toString(mUpdatedState)+
688                        " prev updated: "+Integer.toString(mUpdatedPrevState));
689            } else if (action.equals(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED)) {
690                mUpdatedState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, -1);
691                mUpdatedPrevState = intent.getIntExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, -1);
692                Log.e(TAG, "ACTION_SCO_AUDIO_STATE_UPDATED, state: "+mUpdatedState+" prev state: "+mUpdatedPrevState);
693                mScoStateTxt.setText("changed: "+Integer.toString(mChangedState)+
694                        " updated: "+Integer.toString(mUpdatedState)+
695                        " prev updated: "+Integer.toString(mUpdatedPrevState));
696                if (mForceScoOn && mUpdatedState == AudioManager.SCO_AUDIO_STATE_DISCONNECTED) {
697                    mForceScoOn = false;
698                    mScoButton.setChecked(mForceScoOn);
699                    mAudioManager.stopBluetoothSco();
700                }
701            }
702        }
703    }
704
705}
706