AudioTestFragment.java revision d4f4d754a116ef0d88f5aba5558429d9264c0fc8
1/*
2 * Copyright (C) 2015 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.google.android.car.kitchensink.audio;
18
19import android.car.Car;
20import android.car.CarAppContextManager;
21import android.car.CarAppContextManager.AppContextChangeListener;
22import android.car.CarAppContextManager.AppContextOwnershipChangeListener;
23import android.car.CarNotConnectedException;
24import android.car.media.CarAudioManager;
25import android.content.ComponentName;
26import android.content.Context;
27import android.content.ServiceConnection;
28import android.media.AudioAttributes;
29import android.media.AudioManager;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.IBinder;
33import android.os.Looper;
34import android.support.v4.app.Fragment;
35import android.util.Log;
36import android.view.LayoutInflater;
37import android.view.View;
38import android.view.View.OnClickListener;
39import android.view.ViewGroup;
40import android.widget.Button;
41import android.widget.CompoundButton;
42import android.widget.CompoundButton.OnCheckedChangeListener;
43import android.widget.RadioGroup;
44import android.widget.TextView;
45import android.widget.ToggleButton;
46
47import com.google.android.car.kitchensink.CarEmulator;
48import com.google.android.car.kitchensink.R;
49import com.google.android.car.kitchensink.audio.AudioPlayer.PlayStateListener;
50
51public class AudioTestFragment extends Fragment {
52    private static final String TAG = "CAR.AUDIO.KS";
53    private static final boolean DBG = true;
54
55    private AudioManager mAudioManager;
56    private FocusHandler mAudioFocusHandler;
57    private Button mNavPlayOnce;
58    private Button mVrPlayOnce;
59    private Button mSystemPlayOnce;
60    private Button mMediaPlay;
61    private Button mMediaPlayOnce;
62    private Button mMediaStop;
63    private Button mNavStart;
64    private Button mNavEnd;
65    private Button mVrStart;
66    private Button mVrEnd;
67    private Button mRadioStart;
68    private Button mRadioEnd;
69    private Button mSpeakerPhoneOn;
70    private Button mSpeakerPhoneOff;
71    private Button mMicrophoneOn;
72    private Button mMicrophoneOff;
73    private ToggleButton mEnableMocking;
74    private ToggleButton mRejectFocus;
75
76    private AudioPlayer mMusicPlayer;
77    private AudioPlayer mMusicPlayerShort;
78    private AudioPlayer mNavGuidancePlayer;
79    private AudioPlayer mVrPlayer;
80    private AudioPlayer mSystemPlayer;
81    private AudioPlayer[] mAllPlayers;
82
83    private Handler mHandler;
84    private Context mContext;
85
86    private Car mCar;
87    private CarAppContextManager mAppContextManager;
88    private CarAudioManager mCarAudioManager;
89    private AudioAttributes mMusicAudioAttrib;
90    private AudioAttributes mNavAudioAttrib;
91    private AudioAttributes mVrAudioAttrib;
92    private AudioAttributes mRadioAudioAttrib;
93    private AudioAttributes mSystemSoundAudioAttrib;
94    private CarEmulator mCarEmulator;
95
96    private final AudioManager.OnAudioFocusChangeListener mNavFocusListener =
97            new AudioManager.OnAudioFocusChangeListener() {
98                @Override
99                public void onAudioFocusChange(int focusChange) {
100                    Log.i(TAG, "Nav focus change:" + focusChange);
101                }
102    };
103    private final AudioManager.OnAudioFocusChangeListener mVrFocusListener =
104            new AudioManager.OnAudioFocusChangeListener() {
105                @Override
106                public void onAudioFocusChange(int focusChange) {
107                    Log.i(TAG, "VR focus change:" + focusChange);
108                }
109    };
110    private final AudioManager.OnAudioFocusChangeListener mRadioFocusListener =
111            new AudioManager.OnAudioFocusChangeListener() {
112                @Override
113                public void onAudioFocusChange(int focusChange) {
114                    Log.i(TAG, "Radio focus change:" + focusChange);
115                }
116    };
117
118    private final AppContextOwnershipChangeListener mOwnershipListener =
119            new AppContextOwnershipChangeListener() {
120                @Override
121                public void onAppContextOwnershipLoss(int context) {
122                }
123    };
124
125    private void init() {
126        mContext = getContext();
127        mHandler = new Handler(Looper.getMainLooper());
128        mCar = Car.createCar(mContext, new ServiceConnection() {
129            @Override
130            public void onServiceConnected(ComponentName name, IBinder service) {
131                mAppContextManager =
132                        (CarAppContextManager) mCar.getCarManager(Car.APP_CONTEXT_SERVICE);
133                mAppContextManager.registerContextListener(new AppContextChangeListener() {
134                    @Override
135                    public void onAppContextChange(int activeContexts) {
136                    }
137                }, CarAppContextManager.APP_CONTEXT_NAVIGATION |
138                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
139                mCarAudioManager = (CarAudioManager) mCar.getCarManager(Car.AUDIO_SERVICE);
140                mMusicAudioAttrib = mCarAudioManager.getAudioAttributesForCarUsage(
141                        CarAudioManager.CAR_AUDIO_USAGE_MUSIC);
142                mNavAudioAttrib = mCarAudioManager.getAudioAttributesForCarUsage(
143                        CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE);
144                mVrAudioAttrib = mCarAudioManager.getAudioAttributesForCarUsage(
145                        CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND);
146                mRadioAudioAttrib = mCarAudioManager.getAudioAttributesForCarUsage(
147                        CarAudioManager.CAR_AUDIO_USAGE_RADIO);
148                mSystemSoundAudioAttrib = mCarAudioManager.getAudioAttributesForCarUsage(
149                        CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND);
150                mMusicPlayer = new AudioPlayer(mContext, R.raw.john_harrison_with_the_wichita_state_university_chamber_players_05_summer_mvt_2_adagio,
151                        mMusicAudioAttrib);
152                mMusicPlayerShort = new AudioPlayer(mContext, R.raw.ring_classic_01,
153                        mMusicAudioAttrib);
154                mNavGuidancePlayer = new AudioPlayer(mContext, R.raw.turnright,
155                        mNavAudioAttrib);
156                // no Usage for voice command yet.
157                mVrPlayer = new AudioPlayer(mContext, R.raw.one2six,
158                        mVrAudioAttrib);
159                mSystemPlayer = new AudioPlayer(mContext, R.raw.ring_classic_01,
160                        mSystemSoundAudioAttrib);
161                mAllPlayers = new AudioPlayer[] {
162                        mMusicPlayer,
163                        mMusicPlayerShort,
164                        mNavGuidancePlayer,
165                        mVrPlayer,
166                        mSystemPlayer
167                };
168            }
169            @Override
170            public void onServiceDisconnected(ComponentName name) {
171            }
172        }, Looper.getMainLooper());
173        mCar.connect();
174    }
175
176    @Override
177    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
178        Log.i(TAG, "onCreateView");
179        init();
180        View view = inflater.inflate(R.layout.audio, container, false);
181        mAudioManager = (AudioManager) mContext.getSystemService(
182                Context.AUDIO_SERVICE);
183        mAudioFocusHandler = new FocusHandler(
184                (RadioGroup) view.findViewById(R.id.button_focus_request_selection),
185                (Button) view.findViewById(R.id.button_audio_focus_request),
186                (TextView) view.findViewById(R.id.text_audio_focus_state));
187        mMediaPlay = (Button) view.findViewById(R.id.button_media_play_start);
188        mMediaPlay.setOnClickListener(new OnClickListener() {
189            @Override
190            public void onClick(View v) {
191                mMusicPlayer.start(false, true, AudioManager.AUDIOFOCUS_GAIN);
192            }
193        });
194        mMediaPlayOnce = (Button) view.findViewById(R.id.button_media_play_once);
195        mMediaPlayOnce.setOnClickListener(new OnClickListener() {
196            @Override
197            public void onClick(View v) {
198                mMusicPlayerShort.start(true, false, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT);
199                // play only for 1 sec and stop
200                mHandler.postDelayed(new Runnable() {
201                    @Override
202                    public void run() {
203                        mMusicPlayerShort.stop();
204                    }
205                }, 1000);
206            }
207        });
208        mMediaStop = (Button) view.findViewById(R.id.button_media_play_stop);
209        mMediaStop.setOnClickListener(new OnClickListener() {
210            @Override
211            public void onClick(View v) {
212                mMusicPlayer.stop();
213            }
214        });
215        mNavPlayOnce = (Button) view.findViewById(R.id.button_nav_play_once);
216        mNavPlayOnce.setOnClickListener(new OnClickListener() {
217            @Override
218            public void onClick(View v) {
219                if (mAppContextManager == null) {
220                    return;
221                }
222                if (DBG) {
223                    Log.i(TAG, "Nav start");
224                }
225                if (!mNavGuidancePlayer.isPlaying()) {
226                    mAppContextManager.setActiveContexts(mOwnershipListener,
227                            CarAppContextManager.APP_CONTEXT_NAVIGATION);
228                    mNavGuidancePlayer.start(true, false,
229                            AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
230                            new PlayStateListener() {
231                        @Override
232                        public void onCompletion() {
233                            mAppContextManager.resetActiveContexts(
234                                    CarAppContextManager.APP_CONTEXT_NAVIGATION);
235                        }
236                    });
237                }
238            }
239        });
240        mVrPlayOnce = (Button) view.findViewById(R.id.button_vr_play_once);
241        mVrPlayOnce.setOnClickListener(new OnClickListener() {
242            @Override
243            public void onClick(View v) {
244                if (mAppContextManager == null) {
245                    return;
246                }
247                if (DBG) {
248                    Log.i(TAG, "VR start");
249                }
250                mAppContextManager.setActiveContexts(mOwnershipListener,
251                        CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
252                if (!mVrPlayer.isPlaying()) {
253                    mVrPlayer.start(true, false, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT,
254                            new PlayStateListener() {
255                        @Override
256                        public void onCompletion() {
257                            mAppContextManager.resetActiveContexts(
258                                    CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
259                        }
260                    });
261                }
262            }
263        });
264        mSystemPlayOnce = (Button) view.findViewById(R.id.button_system_play_once);
265        mSystemPlayOnce.setOnClickListener(new OnClickListener() {
266            @Override
267            public void onClick(View v) {
268                if (DBG) {
269                    Log.i(TAG, "System start");
270                }
271                if (!mSystemPlayer.isPlaying()) {
272                    // system sound played without focus
273                    mSystemPlayer.start(false, false, 0);
274                }
275            }
276        });
277        mNavStart = (Button) view.findViewById(R.id.button_nav_start);
278        mNavStart.setOnClickListener(new OnClickListener() {
279            @Override
280            public void onClick(View v) {
281                handleNavStart();
282            }
283        });
284        mNavEnd = (Button) view.findViewById(R.id.button_nav_end);
285        mNavEnd.setOnClickListener(new OnClickListener() {
286            @Override
287            public void onClick(View v) {
288                handleNavEnd();
289            }
290        });
291        mVrStart = (Button) view.findViewById(R.id.button_vr_start);
292        mVrStart.setOnClickListener(new OnClickListener() {
293            @Override
294            public void onClick(View v) {
295                handleVrStart();
296            }
297        });
298        mVrEnd = (Button) view.findViewById(R.id.button_vr_end);
299        mVrEnd.setOnClickListener(new OnClickListener() {
300            @Override
301            public void onClick(View v) {
302                handleVrEnd();
303            }
304        });
305        mRadioStart = (Button) view.findViewById(R.id.button_radio_start);
306        mRadioStart.setOnClickListener(new OnClickListener() {
307            @Override
308            public void onClick(View v) {
309                handleRadioStart();
310            }
311        });
312        mRadioEnd = (Button) view.findViewById(R.id.button_radio_end);
313        mRadioEnd.setOnClickListener(new OnClickListener() {
314            @Override
315            public void onClick(View v) {
316                handleRadioEnd();
317            }
318        });
319        mSpeakerPhoneOn = (Button) view.findViewById(R.id.button_speaker_phone_on);
320        mSpeakerPhoneOn.setOnClickListener(new OnClickListener() {
321            @Override
322            public void onClick(View v) {
323                mAudioManager.setSpeakerphoneOn(true);
324            }
325        });
326        mSpeakerPhoneOff = (Button) view.findViewById(R.id.button_speaker_phone_off);
327        mSpeakerPhoneOff.setOnClickListener(new OnClickListener() {
328            @Override
329            public void onClick(View v) {
330                mAudioManager.setSpeakerphoneOn(false);
331            }
332        });
333        mMicrophoneOn = (Button) view.findViewById(R.id.button_microphone_on);
334        mMicrophoneOn.setOnClickListener(new OnClickListener() {
335            @Override
336            public void onClick(View v) {
337                mAudioManager.setMicrophoneMute(false); // Turn the microphone on.
338            }
339        });
340        mMicrophoneOff = (Button) view.findViewById(R.id.button_microphone_off);
341        mMicrophoneOff.setOnClickListener(new OnClickListener() {
342            @Override
343            public void onClick(View v) {
344                mAudioManager.setMicrophoneMute(true); // Mute the microphone.
345            }
346        });
347
348
349        mRejectFocus = (ToggleButton) view.findViewById(R.id.button_reject_audio_focus);
350        mRejectFocus.setOnCheckedChangeListener(new OnCheckedChangeListener() {
351            @Override
352            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
353                if (mCarEmulator == null) {
354                    return;
355                }
356                if (!mEnableMocking.isChecked()) {
357                    return;
358                }
359                if (isChecked) {
360                    mCarEmulator.setAudioFocusControl(true);
361                } else {
362                    mCarEmulator.setAudioFocusControl(false);
363                }
364            }
365        });
366        mRejectFocus.setActivated(false);
367        mEnableMocking = (ToggleButton) view.findViewById(R.id.button_mock_audio);
368        mEnableMocking.setOnCheckedChangeListener(new OnCheckedChangeListener() {
369            @Override
370            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
371                if (mCarEmulator == null) {
372                    mCarEmulator = new CarEmulator(mCar);
373                }
374                if (isChecked) {
375                    mRejectFocus.setActivated(true);
376                    mCarEmulator.start();
377                } else {
378                    mRejectFocus.setActivated(false);
379                    mCarEmulator.stop();
380                    mCarEmulator = null;
381                }
382            }
383        });
384        return view;
385    }
386
387    @Override
388    public void onDestroyView() {
389        super.onDestroyView();
390        Log.i(TAG, "onDestroyView");
391        if (mCarEmulator != null) {
392            mCarEmulator.setAudioFocusControl(false);
393            mCarEmulator.stop();
394        }
395        for (AudioPlayer p : mAllPlayers) {
396            p.stop();
397        }
398        if (mAudioFocusHandler != null) {
399            mAudioFocusHandler.release();
400            mAudioFocusHandler = null;
401        }
402        if (mAppContextManager != null) {
403            mAppContextManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_NAVIGATION |
404                    CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
405        }
406    }
407
408    private void handleNavStart() {
409        if (mAppContextManager == null) {
410            return;
411        }
412        if (mCarAudioManager == null) {
413            return;
414        }
415        if (DBG) {
416            Log.i(TAG, "Nav start");
417        }
418        mAppContextManager.setActiveContexts(mOwnershipListener,
419                CarAppContextManager.APP_CONTEXT_NAVIGATION);
420        mCarAudioManager.requestAudioFocus(mNavFocusListener, mNavAudioAttrib,
421                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0);
422    }
423
424    private void handleNavEnd() {
425        if (mAppContextManager == null) {
426            return;
427        }
428        if (mCarAudioManager == null) {
429            return;
430        }
431        if (DBG) {
432            Log.i(TAG, "Nav end");
433        }
434        mAppContextManager.resetActiveContexts(
435                CarAppContextManager.APP_CONTEXT_NAVIGATION);
436        mCarAudioManager.abandonAudioFocus(mNavFocusListener, mNavAudioAttrib);
437    }
438
439    private void handleVrStart() {
440        if (mAppContextManager == null) {
441            return;
442        }
443        if (mCarAudioManager == null) {
444            return;
445        }
446        if (DBG) {
447            Log.i(TAG, "VR start");
448        }
449        mAppContextManager.setActiveContexts(mOwnershipListener,
450                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
451        mCarAudioManager.requestAudioFocus(mVrFocusListener, mVrAudioAttrib,
452                AudioManager.AUDIOFOCUS_GAIN_TRANSIENT, 0);
453    }
454
455    private void handleVrEnd() {
456        if (mAppContextManager == null) {
457            return;
458        }
459        if (mCarAudioManager == null) {
460            return;
461        }
462        if (DBG) {
463            Log.i(TAG, "VR end");
464        }
465        mAppContextManager.resetActiveContexts(
466                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
467        mCarAudioManager.abandonAudioFocus(mVrFocusListener, mVrAudioAttrib);
468    }
469
470    private void handleRadioStart() {
471        if (mCarAudioManager == null) {
472            return;
473        }
474        if (DBG) {
475            Log.i(TAG, "Radio start");
476        }
477        mCarAudioManager.requestAudioFocus(mRadioFocusListener, mRadioAudioAttrib,
478                AudioManager.AUDIOFOCUS_GAIN, 0);
479    }
480
481    private void handleRadioEnd() {
482        if (mCarAudioManager == null) {
483            return;
484        }
485        if (DBG) {
486            Log.i(TAG, "Radio end");
487        }
488        mCarAudioManager.abandonAudioFocus(mRadioFocusListener, mRadioAudioAttrib);
489    }
490
491    private class FocusHandler {
492        private static final String AUDIO_FOCUS_STATE_GAIN = "gain";
493        private static final String AUDIO_FOCUS_STATE_RELEASED_UNKNOWN = "released / unknown";
494
495        private final RadioGroup mRequestSelection;
496        private final TextView mText;
497        private final AudioFocusListener mFocusListener;
498
499        public FocusHandler(RadioGroup radioGroup, Button requestButton, TextView text) {
500            mText = text;
501            mRequestSelection = radioGroup;
502            mRequestSelection.check(R.id.focus_gain);
503            setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
504            mFocusListener = new AudioFocusListener();
505            requestButton.setOnClickListener(new OnClickListener() {
506                @Override
507                public void onClick(View v) {
508                    int selectedButtonId = mRequestSelection.getCheckedRadioButtonId();
509                    int focusRequest = AudioManager.AUDIOFOCUS_GAIN;
510                    if (selectedButtonId == R.id.focus_gain_transient_duck) {
511                        focusRequest = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
512                    } else if (selectedButtonId == R.id.focus_release) {
513                        mAudioManager.abandonAudioFocus(mFocusListener);
514                        setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
515                        return;
516                    }
517                    int ret = mAudioManager.requestAudioFocus(mFocusListener,
518                            AudioManager.STREAM_MUSIC, focusRequest);
519                    Log.i(TAG, "requestAudioFocus returned " + ret);
520                    if (ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
521                        setFocusText(AUDIO_FOCUS_STATE_GAIN);
522                    }
523                }
524            });
525        }
526
527        public void release() {
528            abandonAudioFocus();
529        }
530
531        private void abandonAudioFocus() {
532            if (DBG) {
533                Log.i(TAG, "abandonAudioFocus");
534            }
535            mAudioManager.abandonAudioFocus(mFocusListener);
536            setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
537        }
538
539        private void setFocusText(String msg) {
540            mText.setText("focus state:" + msg);
541        }
542
543        private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
544            @Override
545            public void onAudioFocusChange(int focusChange) {
546                Log.i(TAG, "onAudioFocusChange " + focusChange);
547                if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
548                    setFocusText(AUDIO_FOCUS_STATE_GAIN);
549                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
550                    setFocusText("loss");
551                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
552                    setFocusText("loss,transient");
553                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
554                    setFocusText("loss,transient,duck");
555                }
556            }
557        }
558    }
559}
560