/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.tv; import android.app.Activity; import android.content.Context; import android.media.AudioManager; import android.os.Build; import com.android.tv.receiver.AudioCapabilitiesReceiver; import com.android.tv.ui.TunableTvView; import com.android.tv.ui.TunableTvViewPlayingApi; /** A helper class to help {@link MainActivity} to handle audio-related stuffs. */ class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener { private static final float AUDIO_MAX_VOLUME = 1.0f; private static final float AUDIO_MIN_VOLUME = 0.0f; private static final float AUDIO_DUCKING_VOLUME = 0.3f; private final Activity mActivity; private final TunableTvViewPlayingApi mTvView; private final AudioManager mAudioManager; private final AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; private boolean mAc3PassthroughSupported; private int mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; AudioManagerHelper(Activity activity, TunableTvViewPlayingApi tvView) { mActivity = activity; mTvView = tvView; mAudioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver( activity, new AudioCapabilitiesReceiver.OnAc3PassthroughCapabilityChangeListener() { @Override public void onAc3PassthroughCapabilityChange(boolean capability) { mAc3PassthroughSupported = capability; } }); mAudioCapabilitiesReceiver.register(); } /** * Sets suitable volume to {@link TunableTvView} according to the current audio focus. If the * focus status is {@link AudioManager#AUDIOFOCUS_LOSS} and the activity is under PIP mode, this * method will finish the activity. */ void setVolumeByAudioFocusStatus() { if (mTvView.isPlaying()) { switch (mAudioFocusStatus) { case AudioManager.AUDIOFOCUS_GAIN: if (mTvView.isTimeShiftAvailable()) { mTvView.timeshiftPlay(); } else { mTvView.setStreamVolume(AUDIO_MAX_VOLUME); } break; case AudioManager.AUDIOFOCUS_LOSS: if (TvFeatures.PICTURE_IN_PICTURE.isEnabled(mActivity) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mActivity.isInPictureInPictureMode()) { mActivity.finish(); break; } // fall through case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: if (mTvView.isTimeShiftAvailable()) { mTvView.timeshiftPause(); } else { mTvView.setStreamVolume(AUDIO_MIN_VOLUME); } break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: if (mTvView.isTimeShiftAvailable()) { mTvView.timeshiftPause(); } else { mTvView.setStreamVolume(AUDIO_DUCKING_VOLUME); } break; } } } /** * Tries to request audio focus from {@link AudioManager} and set volume according to the * returned result. */ void requestAudioFocus() { int result = mAudioManager.requestAudioFocus( this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); mAudioFocusStatus = (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) ? AudioManager.AUDIOFOCUS_GAIN : AudioManager.AUDIOFOCUS_LOSS; setVolumeByAudioFocusStatus(); } /** Abandons audio focus. */ void abandonAudioFocus() { mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; mAudioManager.abandonAudioFocus(this); } /** Returns {@code true} if the device supports AC3 pass-through. */ boolean isAc3PassthroughSupported() { return mAc3PassthroughSupported; } /** Release the resources the helper class may occupied. */ void release() { mAudioCapabilitiesReceiver.unregister(); } @Override public void onAudioFocusChange(int focusChange) { mAudioFocusStatus = focusChange; setVolumeByAudioFocusStatus(); } }