1 package com.android.tv; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.media.AudioManager; 6 import android.os.Build; 7 8 import com.android.tv.receiver.AudioCapabilitiesReceiver; 9 import com.android.tv.ui.TunableTvView; 10 11 /** 12 * A helper class to help {@link MainActivity} to handle audio-related stuffs. 13 */ 14 class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener { 15 private static final float AUDIO_MAX_VOLUME = 1.0f; 16 private static final float AUDIO_MIN_VOLUME = 0.0f; 17 private static final float AUDIO_DUCKING_VOLUME = 0.3f; 18 19 private final Activity mActivity; 20 private final TunableTvView mTvView; 21 private final AudioManager mAudioManager; 22 private final AudioCapabilitiesReceiver mAudioCapabilitiesReceiver; 23 24 private boolean mAc3PassthroughSupported; 25 private int mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; 26 27 AudioManagerHelper(Activity activity, TunableTvView tvView) { 28 mActivity = activity; 29 mTvView = tvView; 30 mAudioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE); 31 mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(activity, 32 new AudioCapabilitiesReceiver.OnAc3PassthroughCapabilityChangeListener() { 33 @Override 34 public void onAc3PassthroughCapabilityChange(boolean capability) { 35 mAc3PassthroughSupported = capability; 36 } 37 }); 38 mAudioCapabilitiesReceiver.register(); 39 } 40 41 /** 42 * Sets suitable volume to {@link TunableTvView} according to the current audio focus. 43 * If the focus status is {@link AudioManager#AUDIOFOCUS_LOSS} and the activity is under PIP 44 * mode, this method will finish the activity. 45 */ 46 void setVolumeByAudioFocusStatus() { 47 if (mTvView.isPlaying()) { 48 switch (mAudioFocusStatus) { 49 case AudioManager.AUDIOFOCUS_GAIN: 50 mTvView.setStreamVolume(AUDIO_MAX_VOLUME); 51 break; 52 case AudioManager.AUDIOFOCUS_LOSS: 53 if (Features.PICTURE_IN_PICTURE.isEnabled(mActivity) 54 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N 55 && mActivity.isInPictureInPictureMode()) { 56 mActivity.finish(); 57 break; 58 } 59 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: 60 mTvView.setStreamVolume(AUDIO_MIN_VOLUME); 61 break; 62 case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK: 63 mTvView.setStreamVolume(AUDIO_DUCKING_VOLUME); 64 break; 65 } 66 } 67 } 68 69 /** 70 * Tries to request audio focus from {@link AudioManager} and set volume according to the 71 * returned result. 72 */ 73 void requestAudioFocus() { 74 int result = mAudioManager.requestAudioFocus(this, 75 AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); 76 mAudioFocusStatus = (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) ? 77 AudioManager.AUDIOFOCUS_GAIN : AudioManager.AUDIOFOCUS_LOSS; 78 setVolumeByAudioFocusStatus(); 79 } 80 81 /** 82 * Abandons audio focus. 83 */ 84 void abandonAudioFocus() { 85 mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS; 86 mAudioManager.abandonAudioFocus(this); 87 } 88 89 /** 90 * Returns {@code true} if the device supports AC3 pass-through. 91 */ 92 boolean isAc3PassthroughSupported() { 93 return mAc3PassthroughSupported; 94 } 95 96 /** 97 * Release the resources the helper class may occupied. 98 */ 99 void release() { 100 mAudioCapabilitiesReceiver.unregister(); 101 } 102 103 @Override 104 public void onAudioFocusChange(int focusChange) { 105 mAudioFocusStatus = focusChange; 106 setVolumeByAudioFocusStatus(); 107 } 108 } 109