1/*
2 * Copyright (C) 2014 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.android.server.hdmi;
18
19import android.hardware.tv.cec.V1_0.SendMessageResult;
20import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
21
22/**
23 * Action to initiate system audio once AVR is detected on Device discovery action.
24 */
25// Seq #27
26final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction {
27    private final int mAvrAddress;
28
29    // State that waits for <System Audio Mode Status> once send
30    // <Give System Audio Mode Status> to AV Receiver.
31    private static final int STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS = 1;
32
33    SystemAudioAutoInitiationAction(HdmiCecLocalDevice source, int avrAddress) {
34        super(source);
35        mAvrAddress = avrAddress;
36    }
37
38    @Override
39    boolean start() {
40        mState = STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS;
41
42        addTimer(mState, HdmiConfig.TIMEOUT_MS);
43        sendGiveSystemAudioModeStatus();
44        return true;
45    }
46
47    private void sendGiveSystemAudioModeStatus() {
48        sendCommand(HdmiCecMessageBuilder.buildGiveSystemAudioModeStatus(getSourceAddress(),
49                mAvrAddress), new SendMessageCallback() {
50            @Override
51            public void onSendCompleted(int error) {
52                if (error != SendMessageResult.SUCCESS) {
53                    tv().setSystemAudioMode(false);
54                    finish();
55                }
56            }
57        });
58    }
59
60    @Override
61    boolean processCommand(HdmiCecMessage cmd) {
62        if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS
63                || mAvrAddress != cmd.getSource()) {
64            return false;
65        }
66
67        if (cmd.getOpcode() == Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS) {
68            handleSystemAudioModeStatusMessage(HdmiUtils.parseCommandParamSystemAudioStatus(cmd));
69            return true;
70        }
71        return false;
72    }
73
74    private void handleSystemAudioModeStatusMessage(boolean currentSystemAudioMode) {
75        if (!canChangeSystemAudio()) {
76            HdmiLogger.debug("Cannot change system audio mode in auto initiation action.");
77            finish();
78            return;
79        }
80
81        // If System Audio Control feature is enabled, turn on system audio mode when new AVR is
82        // detected. Otherwise, turn off system audio mode.
83        boolean targetSystemAudioMode = tv().isSystemAudioControlFeatureEnabled();
84        if (currentSystemAudioMode != targetSystemAudioMode) {
85            // Start System Audio Control feature actions only if necessary.
86            addAndStartAction(
87                    new SystemAudioActionFromTv(tv(), mAvrAddress, targetSystemAudioMode, null));
88        } else {
89            // If AVR already has correct system audio mode, update target system audio mode
90            // immediately rather than starting feature action.
91            tv().setSystemAudioMode(targetSystemAudioMode);
92        }
93        finish();
94    }
95
96    @Override
97    void handleTimerEvent(int state) {
98        if (mState != state) {
99            return;
100        }
101
102        switch (mState) {
103            case STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS:
104                handleSystemAudioModeStatusTimeout();
105                break;
106        }
107    }
108
109    private void handleSystemAudioModeStatusTimeout() {
110        if (!canChangeSystemAudio()) {
111            HdmiLogger.debug("Cannot change system audio mode in auto initiation action.");
112            finish();
113            return;
114        }
115        // If we can't get the current system audio mode status, just try to turn on/off system
116        // audio mode according to the system audio control setting.
117        addAndStartAction(new SystemAudioActionFromTv(tv(), mAvrAddress,
118                tv().isSystemAudioControlFeatureEnabled(), null));
119        finish();
120    }
121
122    private boolean canChangeSystemAudio() {
123        return !(tv().hasAction(SystemAudioActionFromTv.class)
124               || tv().hasAction(SystemAudioActionFromAvr.class));
125    }
126}
127