SetArcTransmissionStateAction.java revision 63a2e0696ce2a04fbe0f1f00cfe9c93189f944da
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.HdmiCec;
20import android.hardware.hdmi.HdmiCecMessage;
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 service an instance of {@link HdmiControlService}
43     * @param sourceAddress logical address to be used as source address
44     * @param enabled whether to enable ARC Transmission channel
45     */
46    SetArcTransmissionStateAction(HdmiControlService service, int sourceAddress, int avrAddress,
47            boolean enabled) {
48        super(service, sourceAddress);
49        HdmiUtils.verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV);
50        HdmiUtils.verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM);
51        mAvrAddress = avrAddress;
52        mEnabled = enabled;
53    }
54
55    @Override
56    boolean start() {
57        if (mEnabled) {
58            sendReportArcInitiated();
59        } else {
60            setArcStatus(false);
61            finish();
62        }
63        return true;
64    }
65
66    private void sendReportArcInitiated() {
67        HdmiCecMessage command =
68                HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress);
69        sendCommand(command, new HdmiControlService.SendMessageCallback() {
70            @Override
71            public void onSendCompleted(int error) {
72                if (error == HdmiControlService.SEND_RESULT_SUCCESS) {
73                    // Enable ARC status immediately after sending <Report Arc Initiated>.
74                    // If AVR responds with <Feature Abort>, disable ARC status again.
75                    // This is different from spec that says that turns ARC status to
76                    // "Enabled" if <Report ARC Initiated> is acknowledged and no
77                    // <Feature Abort> is received.
78                    // But implemented this way to save the time having to wait for
79                    // <Feature Abort>.
80                    setArcStatus(true);
81                    // If succeeds to send <Report ARC Initiated>, wait general timeout
82                    // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
83                    mState = STATE_WAITING_TIMEOUT;
84                    addTimer(mState, TIMEOUT_MS);
85                } else {
86                    // If fails to send <Report ARC Initiated>, disable ARC and
87                    // send <Report ARC Terminated> directly.
88                    setArcStatus(false);
89                    finish();
90                }
91            }
92        });
93    }
94
95    private void setArcStatus(boolean enabled) {
96        boolean wasEnabled = mService.setArcStatus(enabled);
97        Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled);
98
99        // If enabled before and set to "disabled" and send <Report Arc Terminated> to
100        // av reciever.
101        if (!enabled && wasEnabled) {
102            sendCommand(
103                    HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress));
104        }
105    }
106
107    @Override
108    boolean processCommand(HdmiCecMessage cmd) {
109        if (mState != STATE_WAITING_TIMEOUT) {
110            return false;
111        }
112
113        int opcode = cmd.getOpcode();
114        if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) {
115            setArcStatus(false);
116        }
117        finish();
118        return true;
119    }
120
121    @Override
122    void handleTimerEvent(int state) {
123        if (mState != state || mState != STATE_WAITING_TIMEOUT) {
124            return;
125        }
126        // Expire timeout for <Feature Abort>.
127        finish();
128    }
129}
130