SetArcTransmissionStateAction.java revision c0c20d0522d7756d80f011e7a54bf3b51c78df41
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.hdmi.HdmiCecDeviceInfo;
20
21import android.util.Slog;
22
23/**
24 * Feature action that handles enabling/disabling of ARC transmission channel.
25 * Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver.
26 * If it fails or it gets <Terminate ARC>, TV just disables ARC.
27 */
28final class SetArcTransmissionStateAction extends FeatureAction {
29    private static final String TAG = "SetArcTransmissionStateAction";
30
31    // State in which the action sent <Rerpot Arc Initiated> and
32    // is waiting for time out. If it receives <Feature Abort> within timeout
33    // ARC should be disabled.
34    private static final int STATE_WAITING_TIMEOUT = 1;
35
36    private final boolean mEnabled;
37    private final int mAvrAddress;
38
39    /**
40     * @Constructor
41     *
42     * @param source {@link HdmiCecLocalDevice} instance
43     * @param enabled whether to enable ARC Transmission channel
44     */
45    SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress,
46            boolean enabled) {
47        super(source);
48        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiCecDeviceInfo.DEVICE_TV);
49        HdmiUtils.verifyAddressType(avrAddress, HdmiCecDeviceInfo.DEVICE_AUDIO_SYSTEM);
50        mAvrAddress = avrAddress;
51        mEnabled = enabled;
52    }
53
54    @Override
55    boolean start() {
56        if (mEnabled) {
57            sendReportArcInitiated();
58        } else {
59            setArcStatus(false);
60            finish();
61        }
62        return true;
63    }
64
65    private void sendReportArcInitiated() {
66        HdmiCecMessage command =
67                HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress);
68        sendCommand(command, new HdmiControlService.SendMessageCallback() {
69            @Override
70            public void onSendCompleted(int error) {
71                if (error == Constants.SEND_RESULT_SUCCESS) {
72                    // Enable ARC status immediately after sending <Report Arc Initiated>.
73                    // If AVR responds with <Feature Abort>, disable ARC status again.
74                    // This is different from spec that says that turns ARC status to
75                    // "Enabled" if <Report ARC Initiated> is acknowledged and no
76                    // <Feature Abort> is received.
77                    // But implemented this way to save the time having to wait for
78                    // <Feature Abort>.
79                    setArcStatus(true);
80                    // If succeeds to send <Report ARC Initiated>, wait general timeout
81                    // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
82                    mState = STATE_WAITING_TIMEOUT;
83                    addTimer(mState, TIMEOUT_MS);
84                } else {
85                    // If fails to send <Report ARC Initiated>, disable ARC and
86                    // send <Report ARC Terminated> directly.
87                    setArcStatus(false);
88                    finish();
89                }
90            }
91        });
92    }
93
94    private void setArcStatus(boolean enabled) {
95        boolean wasEnabled = tv().setArcStatus(enabled);
96        Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled);
97
98        // If enabled before and set to "disabled" and send <Report Arc Terminated> to
99        // av reciever.
100        if (!enabled && wasEnabled) {
101            sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
102                    mAvrAddress));
103        }
104    }
105
106    @Override
107    boolean processCommand(HdmiCecMessage cmd) {
108        if (mState != STATE_WAITING_TIMEOUT) {
109            return false;
110        }
111
112        int opcode = cmd.getOpcode();
113        if (opcode == Constants.MESSAGE_FEATURE_ABORT) {
114            setArcStatus(false);
115        }
116        finish();
117        return true;
118    }
119
120    @Override
121    void handleTimerEvent(int state) {
122        if (mState != state || mState != STATE_WAITING_TIMEOUT) {
123            return;
124        }
125        // Expire timeout for <Feature Abort>.
126        finish();
127    }
128}
129