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