AudioTestFragment.java revision a6521cd799e509b03ecbeea3b05f1dd5c0379387
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.CarNotConnectedException;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.ServiceConnection;
26import android.media.AudioAttributes;
27import android.media.AudioManager;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.Looper;
32import android.support.v4.app.Fragment;
33import android.util.Log;
34import android.view.LayoutInflater;
35import android.view.View;
36import android.view.View.OnClickListener;
37import android.view.ViewGroup;
38import android.widget.Button;
39import android.widget.CompoundButton;
40import android.widget.CompoundButton.OnCheckedChangeListener;
41import android.widget.RadioGroup;
42import android.widget.TextView;
43import android.widget.ToggleButton;
44
45import com.google.android.car.kitchensink.CarEmulator;
46import com.google.android.car.kitchensink.R;
47import com.google.android.car.kitchensink.audio.AudioPlayer.PlayStateListener;
48
49public class AudioTestFragment extends Fragment {
50    private static final String TAG = "AudioTest";
51    private static final boolean DBG = true;
52
53    private AudioManager mAudioManager;
54    private FocusHandler mAudioFocusHandler;
55    private Button mNavPlayOnce;
56    private Button mVrPlayOnce;
57    private Button mSystemPlayOnce;
58    private Button mMediaPlay;
59    private Button mMediaPlayOnce;
60    private Button mMediaStop;
61    private Button mNavFocusStart;
62    private Button mNavFocusEnd;
63    private Button mVrFocusStart;
64    private Button mVrFocusEnd;
65    private Button mSpeakerPhoneOn;
66    private Button mSpeakerPhoneOff;
67    private Button mMicrophoneOn;
68    private Button mMicrophoneOff;
69    private ToggleButton mEnableMocking;
70    private ToggleButton mRejectFocus;
71
72    private final AudioPlayer mMusicPlayer;
73    private final AudioPlayer mMusicPlayerShort;
74    private final AudioPlayer mNavGuidancePlayer;
75    private final AudioPlayer mVrPlayer;
76    private final AudioPlayer mSystemPlayer;
77    private final AudioPlayer[] mAllPlayers;
78
79    private final Handler mHandler;
80    private final Context mContext;
81
82    private final Car mCar;
83    private CarAppContextManager mAppContextManager;
84    private CarEmulator mCarEmulator;
85
86    public AudioTestFragment(Context context) {
87        mContext = context;
88        mMusicPlayer = new AudioPlayer(mContext, R.raw.john_harrison_with_the_wichita_state_university_chamber_players_05_summer_mvt_2_adagio,
89                (new AudioAttributes.Builder()).
90                    setUsage(AudioAttributes.USAGE_MEDIA).
91                    setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());
92        mMusicPlayerShort = new AudioPlayer(mContext, R.raw.ring_classic_01,
93                (new AudioAttributes.Builder()).
94                setUsage(AudioAttributes.USAGE_MEDIA).
95                setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build());
96        mNavGuidancePlayer = new AudioPlayer(mContext, R.raw.turnright,
97                (new AudioAttributes.Builder()).
98                    setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE).
99                    setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build());
100        // no Usage for voice command yet.
101        mVrPlayer = new AudioPlayer(mContext, R.raw.one2six,
102                (new AudioAttributes.Builder()).
103                setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).
104                setContentType(AudioAttributes.CONTENT_TYPE_SPEECH).build());
105        mSystemPlayer = new AudioPlayer(mContext, R.raw.ring_classic_01,
106                (new AudioAttributes.Builder()).
107                setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION).
108                setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION).build());
109        mAllPlayers = new AudioPlayer[] {
110                mMusicPlayer,
111                mMusicPlayerShort,
112                mNavGuidancePlayer,
113                mVrPlayer,
114                mSystemPlayer
115        };
116        mHandler = new Handler(Looper.getMainLooper());
117        mCar = Car.createCar(mContext, new ServiceConnection() {
118            @Override
119            public void onServiceConnected(ComponentName name, IBinder service) {
120                mAppContextManager =
121                        (CarAppContextManager) mCar.getCarManager(Car.APP_CONTEXT_SERVICE);
122                mAppContextManager.registerContextListener(new AppContextChangeListener() {
123
124                    @Override
125                    public void onAppContextOwnershipLoss(int context) {
126                    }
127
128                    @Override
129                    public void onAppContextChange(int activeContexts) {
130                    }
131                }, CarAppContextManager.APP_CONTEXT_NAVIGATION |
132                CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
133            }
134            @Override
135            public void onServiceDisconnected(ComponentName name) {
136            }
137        }, Looper.getMainLooper());
138        mCar.connect();
139    }
140
141    @Override
142    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
143        Log.i(TAG, "onCreateView");
144        View view = inflater.inflate(R.layout.audio, container, false);
145        mAudioManager = (AudioManager) mContext.getSystemService(
146                Context.AUDIO_SERVICE);
147        mAudioFocusHandler = new FocusHandler(
148                (RadioGroup) view.findViewById(R.id.button_focus_request_selection),
149                (Button) view.findViewById(R.id.button_audio_focus_request),
150                (TextView) view.findViewById(R.id.text_audio_focus_state));
151        mMediaPlay = (Button) view.findViewById(R.id.button_media_play_start);
152        mMediaPlay.setOnClickListener(new OnClickListener() {
153            @Override
154            public void onClick(View v) {
155                mMusicPlayer.start(false, true);
156            }
157        });
158        mMediaPlayOnce = (Button) view.findViewById(R.id.button_media_play_once);
159        mMediaPlayOnce.setOnClickListener(new OnClickListener() {
160            @Override
161            public void onClick(View v) {
162                mMusicPlayerShort.start(true, false);
163                // play only for 1 sec and stop
164                mHandler.postDelayed(new Runnable() {
165                    @Override
166                    public void run() {
167                        mMusicPlayerShort.stop();
168                    }
169                }, 1000);
170            }
171        });
172        mMediaStop = (Button) view.findViewById(R.id.button_media_play_stop);
173        mMediaStop.setOnClickListener(new OnClickListener() {
174            @Override
175            public void onClick(View v) {
176                mMusicPlayer.stop();
177            }
178        });
179        mNavPlayOnce = (Button) view.findViewById(R.id.button_nav_play_once);
180        mNavPlayOnce.setOnClickListener(new OnClickListener() {
181            @Override
182            public void onClick(View v) {
183                if (mAppContextManager == null) {
184                    return;
185                }
186                if (DBG) {
187                    Log.i(TAG, "Nav start");
188                }
189                if (!mNavGuidancePlayer.isPlaying()) {
190                    mAppContextManager.setActiveContexts(
191                            CarAppContextManager.APP_CONTEXT_NAVIGATION);
192                    mNavGuidancePlayer.start(true, false, new PlayStateListener() {
193                        @Override
194                        public void onCompletion() {
195                            mAppContextManager.resetActiveContexts(
196                                    CarAppContextManager.APP_CONTEXT_NAVIGATION);
197                        }
198                    });
199                }
200            }
201        });
202        mVrPlayOnce = (Button) view.findViewById(R.id.button_vr_play_once);
203        mVrPlayOnce.setOnClickListener(new OnClickListener() {
204            @Override
205            public void onClick(View v) {
206                if (mAppContextManager == null) {
207                    return;
208                }
209                if (DBG) {
210                    Log.i(TAG, "VR start");
211                }
212                mAppContextManager.setActiveContexts(
213                        CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
214                if (!mVrPlayer.isPlaying()) {
215                    mVrPlayer.start(true, false, new PlayStateListener() {
216                        @Override
217                        public void onCompletion() {
218                            mAppContextManager.resetActiveContexts(
219                                    CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
220                        }
221                    });
222                }
223            }
224        });
225        mSystemPlayOnce = (Button) view.findViewById(R.id.button_system_play_once);
226        mSystemPlayOnce.setOnClickListener(new OnClickListener() {
227            @Override
228            public void onClick(View v) {
229                if (DBG) {
230                    Log.i(TAG, "System start");
231                }
232                if (!mSystemPlayer.isPlaying()) {
233                    // system sound played without focus
234                    mSystemPlayer.start(false, false);
235                }
236            }
237        });
238        mNavFocusStart = (Button) view.findViewById(R.id.button_nav_start);
239        mNavFocusStart.setOnClickListener(new OnClickListener() {
240            @Override
241            public void onClick(View v) {
242                if (mAppContextManager == null) {
243                    return;
244                }
245                if (DBG) {
246                    Log.i(TAG, "Nav focus request");
247                }
248                mAppContextManager.setActiveContexts(
249                        CarAppContextManager.APP_CONTEXT_NAVIGATION);
250            }
251        });
252        mNavFocusEnd = (Button) view.findViewById(R.id.button_nav_end);
253        mNavFocusEnd.setOnClickListener(new OnClickListener() {
254            @Override
255            public void onClick(View v) {
256                if (mAppContextManager == null) {
257                    return;
258                }
259                if (DBG) {
260                    Log.i(TAG, "Nav focus release");
261                }
262                mAppContextManager.resetActiveContexts(
263                        CarAppContextManager.APP_CONTEXT_NAVIGATION);
264            }
265        });
266        mVrFocusStart = (Button) view.findViewById(R.id.button_vr_start);
267        mVrFocusStart.setOnClickListener(new OnClickListener() {
268            @Override
269            public void onClick(View v) {
270                if (mAppContextManager == null) {
271                    return;
272                }
273                if (DBG) {
274                    Log.i(TAG, "VR request");
275                }
276                mAppContextManager.setActiveContexts(
277                        CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
278            }
279        });
280        mVrFocusEnd = (Button) view.findViewById(R.id.button_vr_end);
281        mVrFocusEnd.setOnClickListener(new OnClickListener() {
282            @Override
283            public void onClick(View v) {
284                if (mAppContextManager == null) {
285                    return;
286                }
287                if (DBG) {
288                    Log.i(TAG, "VR request");
289                }
290                mAppContextManager.resetActiveContexts(
291                        CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
292            }
293        });
294        mSpeakerPhoneOn = (Button) view.findViewById(R.id.button_speaker_phone_on);
295        mSpeakerPhoneOn.setOnClickListener(new OnClickListener() {
296            @Override
297            public void onClick(View v) {
298                mAudioManager.setSpeakerphoneOn(true);
299            }
300        });
301        mSpeakerPhoneOff = (Button) view.findViewById(R.id.button_speaker_phone_off);
302        mSpeakerPhoneOff.setOnClickListener(new OnClickListener() {
303            @Override
304            public void onClick(View v) {
305                mAudioManager.setSpeakerphoneOn(false);
306            }
307        });
308        mMicrophoneOn = (Button) view.findViewById(R.id.button_microphone_on);
309        mMicrophoneOn.setOnClickListener(new OnClickListener() {
310            @Override
311            public void onClick(View v) {
312                mAudioManager.setMicrophoneMute(false); // Turn the microphone on.
313            }
314        });
315        mMicrophoneOff = (Button) view.findViewById(R.id.button_microphone_off);
316        mMicrophoneOff.setOnClickListener(new OnClickListener() {
317            @Override
318            public void onClick(View v) {
319                mAudioManager.setMicrophoneMute(true); // Mute the microphone.
320            }
321        });
322
323
324        mRejectFocus = (ToggleButton) view.findViewById(R.id.button_reject_audio_focus);
325        mRejectFocus.setOnCheckedChangeListener(new OnCheckedChangeListener() {
326            @Override
327            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
328                if (mCarEmulator == null) {
329                    return;
330                }
331                if (!mEnableMocking.isChecked()) {
332                    return;
333                }
334                if (isChecked) {
335                    mCarEmulator.setAudioFocusControl(true);
336                } else {
337                    mCarEmulator.setAudioFocusControl(false);
338                }
339            }
340        });
341        mRejectFocus.setActivated(false);
342        mEnableMocking = (ToggleButton) view.findViewById(R.id.button_mock_audio);
343        mEnableMocking.setOnCheckedChangeListener(new OnCheckedChangeListener() {
344            @Override
345            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
346                if (mCarEmulator == null) {
347                    mCarEmulator = new CarEmulator(mCar);
348                }
349                if (isChecked) {
350                    mRejectFocus.setActivated(true);
351                    mCarEmulator.start();
352                } else {
353                    mRejectFocus.setActivated(false);
354                    mCarEmulator.stop();
355                    mCarEmulator = null;
356                }
357            }
358        });
359        return view;
360    }
361
362    @Override
363    public void onDestroyView() {
364        Log.i(TAG, "onDestroyView");
365        super.onDestroyView();
366        if (mCarEmulator != null) {
367            mCarEmulator.setAudioFocusControl(false);
368            mCarEmulator.stop();
369        }
370        for (AudioPlayer p : mAllPlayers) {
371            p.stop();
372        }
373        if (mAudioFocusHandler != null) {
374            mAudioFocusHandler.release();
375            mAudioFocusHandler = null;
376        }
377        if (mAppContextManager != null) {
378            mAppContextManager.resetActiveContexts(CarAppContextManager.APP_CONTEXT_NAVIGATION |
379                    CarAppContextManager.APP_CONTEXT_VOICE_COMMAND);
380        }
381    }
382
383    private class FocusHandler {
384        private static final String AUDIO_FOCUS_STATE_GAIN = "gain";
385        private static final String AUDIO_FOCUS_STATE_RELEASED_UNKNOWN = "released / unknown";
386
387        private final RadioGroup mRequestSelection;
388        private final TextView mText;
389        private final AudioFocusListener mFocusListener;
390
391        public FocusHandler(RadioGroup radioGroup, Button requestButton, TextView text) {
392            mText = text;
393            mRequestSelection = radioGroup;
394            mRequestSelection.check(R.id.focus_gain);
395            setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
396            mFocusListener = new AudioFocusListener();
397            requestButton.setOnClickListener(new OnClickListener() {
398                @Override
399                public void onClick(View v) {
400                    int selectedButtonId = mRequestSelection.getCheckedRadioButtonId();
401                    int focusRequest = AudioManager.AUDIOFOCUS_GAIN;
402                    if (selectedButtonId == R.id.focus_gain_transient_duck) {
403                        focusRequest = AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK;
404                    } else if (selectedButtonId == R.id.focus_release) {
405                        mAudioManager.abandonAudioFocus(mFocusListener);
406                        setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
407                        return;
408                    }
409                    int ret = mAudioManager.requestAudioFocus(mFocusListener,
410                            AudioManager.STREAM_MUSIC, focusRequest);
411                    Log.i(TAG, "requestAudioFocus returned " + ret);
412                    if (ret == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
413                        setFocusText(AUDIO_FOCUS_STATE_GAIN);
414                    }
415                }
416            });
417        }
418
419        public void release() {
420            abandonAudioFocus();
421        }
422
423        private void abandonAudioFocus() {
424            if (DBG) {
425                Log.i(TAG, "abandonAudioFocus");
426            }
427            mAudioManager.abandonAudioFocus(mFocusListener);
428            setFocusText(AUDIO_FOCUS_STATE_RELEASED_UNKNOWN);
429        }
430
431        private void setFocusText(String msg) {
432            mText.setText("focus state:" + msg);
433        }
434
435        private class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener {
436            @Override
437            public void onAudioFocusChange(int focusChange) {
438                Log.i(TAG, "onAudioFocusChange " + focusChange);
439                if (focusChange == AudioManager.AUDIOFOCUS_GAIN) {
440                    setFocusText(AUDIO_FOCUS_STATE_GAIN);
441                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) {
442                    setFocusText("loss");
443                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
444                    setFocusText("loss,transient");
445                } else if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
446                    setFocusText("loss,transient,duck");
447                }
448            }
449        }
450    }
451}
452