167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang/*
267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Copyright (C) 2014 The Android Open Source Project
367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang *
467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License");
567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * you may not use this file except in compliance with the License.
667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * You may obtain a copy of the License at
767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang *
867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang *      http://www.apache.org/licenses/LICENSE-2.0
967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang *
1067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Unless required by applicable law or agreed to in writing, software
1167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS,
1267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * See the License for the specific language governing permissions and
1467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * limitations under the License.
1567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */
1667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
1767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangpackage com.android.server.hdmi;
1867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo;
2067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.util.Slog;
2167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
2267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang/**
2367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Feature action that handles enabling/disabling of ARC transmission channel.
2467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver.
2567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * If it fails or it gets <Terminate ARC>, TV just disables ARC.
2667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */
27b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jangfinal class SetArcTransmissionStateAction extends HdmiCecFeatureAction {
2867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    private static final String TAG = "SetArcTransmissionStateAction";
2967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
3067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    // State in which the action sent <Rerpot Arc Initiated> and
3167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    // is waiting for time out. If it receives <Feature Abort> within timeout
3267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    // ARC should be disabled.
3367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    private static final int STATE_WAITING_TIMEOUT = 1;
3467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
3567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    private final boolean mEnabled;
3667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    private final int mAvrAddress;
3767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
3867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    /**
3967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * @Constructor
4067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     *
4179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang     * @param source {@link HdmiCecLocalDevice} instance
4267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     * @param enabled whether to enable ARC Transmission channel
4367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang     */
4479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang    SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress,
4567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            boolean enabled) {
4679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        super(source);
4761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang        HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV);
4861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang        HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM);
4967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mAvrAddress = avrAddress;
5067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        mEnabled = enabled;
5167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
5267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
5367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    @Override
5467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    boolean start() {
5571651d37125a5fe7339fb5f140876c891a8275dfJinsuk Kim        // Seq #37.
5667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        if (mEnabled) {
57087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim            // Enable ARC status immediately before sending <Report Arc Initiated>.
582e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // If AVR responds with <Feature Abort>, disable ARC status again.
592e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // This is different from spec that says that turns ARC status to
602e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // "Enabled" if <Report ARC Initiated> is acknowledged and no
612e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // <Feature Abort> is received.
622e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // But implemented this way to save the time having to wait for
632e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // <Feature Abort>.
642e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            setArcStatus(true);
652e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // If succeeds to send <Report ARC Initiated>, wait general timeout
662e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
672e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            mState = STATE_WAITING_TIMEOUT;
682e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang            addTimer(mState, HdmiConfig.TIMEOUT_MS);
69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            sendReportArcInitiated();
7067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        } else {
7167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            setArcStatus(false);
7267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            finish();
7367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
7467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        return true;
7567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
7667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
77d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    private void sendReportArcInitiated() {
78d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        HdmiCecMessage command =
7979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress);
80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        sendCommand(command, new HdmiControlService.SendMessageCallback() {
81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            @Override
82d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            public void onSendCompleted(int error) {
83087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                switch (error) {
84087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                    case Constants.SEND_RESULT_SUCCESS:
85087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                    case Constants.SEND_RESULT_BUSY:
86087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                    case Constants.SEND_RESULT_FAILURE:
87087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        // The result of the command transmission, unless it is an obvious
88087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        // failure indicated by the target device (or lack thereof), should
89087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        // not affect the ARC status. Ignores it silently.
90087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        break;
91087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                    case Constants.SEND_RESULT_NAK:
92087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        // If <Report ARC Initiated> is negatively ack'ed, disable ARC and
93087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        // send <Report ARC Terminated> directly.
94087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        setArcStatus(false);
95087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        HdmiLogger.debug("Failed to send <Report Arc Initiated>.");
96087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        finish();
97087839755d311b09f40a1b9db1d09c9c8bdf9872Jinsuk Kim                        break;
98d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang                }
99d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang            }
100d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang        });
101d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang    }
102d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang
10367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    private void setArcStatus(boolean enabled) {
10479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang        boolean wasEnabled = tv().setArcStatus(enabled);
105c94ac5cffc982898bc4f7a5d97d8fad5520ff444Jungshik Jang        Slog.i(TAG, "Change arc status [old:" + wasEnabled + ", new:" + enabled + "]");
10667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
10767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // If enabled before and set to "disabled" and send <Report Arc Terminated> to
10867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // av reciever.
10967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        if (!enabled && wasEnabled) {
11079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang            sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(),
11179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang                    mAvrAddress));
11267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
11367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
11467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
11567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    @Override
11667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    boolean processCommand(HdmiCecMessage cmd) {
11767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        if (mState != STATE_WAITING_TIMEOUT) {
11867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            return false;
11967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
12067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
12167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        int opcode = cmd.getOpcode();
122c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim        if (opcode == Constants.MESSAGE_FEATURE_ABORT) {
123339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang            int originalOpcode = cmd.getParams()[0] & 0xFF;
124339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang            if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) {
1252e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang                HdmiLogger.debug("Feature aborted for <Report Arc Initiated>");
126339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang                setArcStatus(false);
127339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang                finish();
128339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang                return true;
129339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang            }
13067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
131339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang        return false;
13267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
13367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang
13467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    @Override
13567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    void handleTimerEvent(int state) {
13667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        if (mState != state || mState != STATE_WAITING_TIMEOUT) {
13767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang            return;
13867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        }
13967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        // Expire timeout for <Feature Abort>.
14067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang        finish();
14167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang    }
14267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang}
143