| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.server.hdmi; |
| |
| import android.hardware.hdmi.HdmiDeviceInfo; |
| import android.hardware.tv.cec.V1_0.SendMessageResult; |
| import android.util.Slog; |
| |
| /** |
| * Feature action that handles enabling/disabling of ARC transmission channel. |
| * Once TV gets <Initiate ARC>, TV sends <Report ARC Initiated> to AV Receiver. |
| * If it fails or it gets <Terminate ARC>, TV just disables ARC. |
| */ |
| final class SetArcTransmissionStateAction extends HdmiCecFeatureAction { |
| private static final String TAG = "SetArcTransmissionStateAction"; |
| |
| // State in which the action sent <Rerpot Arc Initiated> and |
| // is waiting for time out. If it receives <Feature Abort> within timeout |
| // ARC should be disabled. |
| private static final int STATE_WAITING_TIMEOUT = 1; |
| |
| private final boolean mEnabled; |
| private final int mAvrAddress; |
| |
| /** |
| * @Constructor |
| * |
| * @param source {@link HdmiCecLocalDevice} instance |
| * @param enabled whether to enable ARC Transmission channel |
| */ |
| SetArcTransmissionStateAction(HdmiCecLocalDevice source, int avrAddress, |
| boolean enabled) { |
| super(source); |
| HdmiUtils.verifyAddressType(getSourceAddress(), HdmiDeviceInfo.DEVICE_TV); |
| HdmiUtils.verifyAddressType(avrAddress, HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM); |
| mAvrAddress = avrAddress; |
| mEnabled = enabled; |
| } |
| |
| @Override |
| boolean start() { |
| // Seq #37. |
| if (mEnabled) { |
| // Enable ARC status immediately before sending <Report Arc Initiated>. |
| // If AVR responds with <Feature Abort>, disable ARC status again. |
| // This is different from spec that says that turns ARC status to |
| // "Enabled" if <Report ARC Initiated> is acknowledged and no |
| // <Feature Abort> is received. |
| // But implemented this way to save the time having to wait for |
| // <Feature Abort>. |
| setArcStatus(true); |
| // If succeeds to send <Report ARC Initiated>, wait general timeout |
| // to check whether there is no <Feature Abort> for <Report ARC Initiated>. |
| mState = STATE_WAITING_TIMEOUT; |
| addTimer(mState, HdmiConfig.TIMEOUT_MS); |
| sendReportArcInitiated(); |
| } else { |
| setArcStatus(false); |
| finish(); |
| } |
| return true; |
| } |
| |
| private void sendReportArcInitiated() { |
| HdmiCecMessage command = |
| HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress); |
| sendCommand(command, new HdmiControlService.SendMessageCallback() { |
| @Override |
| public void onSendCompleted(int error) { |
| switch (error) { |
| case SendMessageResult.SUCCESS: |
| case SendMessageResult.BUSY: |
| case SendMessageResult.FAIL: |
| // The result of the command transmission, unless it is an obvious |
| // failure indicated by the target device (or lack thereof), should |
| // not affect the ARC status. Ignores it silently. |
| break; |
| case SendMessageResult.NACK: |
| // If <Report ARC Initiated> is negatively ack'ed, disable ARC and |
| // send <Report ARC Terminated> directly. |
| setArcStatus(false); |
| HdmiLogger.debug("Failed to send <Report Arc Initiated>."); |
| finish(); |
| break; |
| } |
| } |
| }); |
| } |
| |
| private void setArcStatus(boolean enabled) { |
| boolean wasEnabled = tv().setArcStatus(enabled); |
| Slog.i(TAG, "Change arc status [old:" + wasEnabled + ", new:" + enabled + "]"); |
| |
| // If enabled before and set to "disabled" and send <Report Arc Terminated> to |
| // av reciever. |
| if (!enabled && wasEnabled) { |
| sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(), |
| mAvrAddress)); |
| } |
| } |
| |
| @Override |
| boolean processCommand(HdmiCecMessage cmd) { |
| if (mState != STATE_WAITING_TIMEOUT) { |
| return false; |
| } |
| |
| int opcode = cmd.getOpcode(); |
| if (opcode == Constants.MESSAGE_FEATURE_ABORT) { |
| int originalOpcode = cmd.getParams()[0] & 0xFF; |
| if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) { |
| HdmiLogger.debug("Feature aborted for <Report Arc Initiated>"); |
| setArcStatus(false); |
| finish(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| @Override |
| void handleTimerEvent(int state) { |
| if (mState != state || mState != STATE_WAITING_TIMEOUT) { |
| return; |
| } |
| // Expire timeout for <Feature Abort>. |
| finish(); |
| } |
| } |