1package com.android.tv;
2
3import android.app.Activity;
4import android.content.Context;
5import android.media.AudioManager;
6import android.os.Build;
7
8import com.android.tv.receiver.AudioCapabilitiesReceiver;
9import com.android.tv.ui.TunableTvView;
10
11/**
12 * A helper class to help {@link MainActivity} to handle audio-related stuffs.
13 */
14class 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