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.HdmiDeviceInfo; 20import 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 */ 27final 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 // Seq #37. 56 if (mEnabled) { 57 // Enable ARC status immediately before sending <Report Arc Initiated>. 58 // If AVR responds with <Feature Abort>, disable ARC status again. 59 // This is different from spec that says that turns ARC status to 60 // "Enabled" if <Report ARC Initiated> is acknowledged and no 61 // <Feature Abort> is received. 62 // But implemented this way to save the time having to wait for 63 // <Feature Abort>. 64 setArcStatus(true); 65 // If succeeds to send <Report ARC Initiated>, wait general timeout 66 // to check whether there is no <Feature Abort> for <Report ARC Initiated>. 67 mState = STATE_WAITING_TIMEOUT; 68 addTimer(mState, HdmiConfig.TIMEOUT_MS); 69 sendReportArcInitiated(); 70 } else { 71 setArcStatus(false); 72 finish(); 73 } 74 return true; 75 } 76 77 private void sendReportArcInitiated() { 78 HdmiCecMessage command = 79 HdmiCecMessageBuilder.buildReportArcInitiated(getSourceAddress(), mAvrAddress); 80 sendCommand(command, new HdmiControlService.SendMessageCallback() { 81 @Override 82 public void onSendCompleted(int error) { 83 switch (error) { 84 case Constants.SEND_RESULT_SUCCESS: 85 case Constants.SEND_RESULT_BUSY: 86 case Constants.SEND_RESULT_FAILURE: 87 // The result of the command transmission, unless it is an obvious 88 // failure indicated by the target device (or lack thereof), should 89 // not affect the ARC status. Ignores it silently. 90 break; 91 case Constants.SEND_RESULT_NAK: 92 // If <Report ARC Initiated> is negatively ack'ed, disable ARC and 93 // send <Report ARC Terminated> directly. 94 setArcStatus(false); 95 HdmiLogger.debug("Failed to send <Report Arc Initiated>."); 96 finish(); 97 break; 98 } 99 } 100 }); 101 } 102 103 private void setArcStatus(boolean enabled) { 104 boolean wasEnabled = tv().setArcStatus(enabled); 105 Slog.i(TAG, "Change arc status [old:" + wasEnabled + ", new:" + enabled + "]"); 106 107 // If enabled before and set to "disabled" and send <Report Arc Terminated> to 108 // av reciever. 109 if (!enabled && wasEnabled) { 110 sendCommand(HdmiCecMessageBuilder.buildReportArcTerminated(getSourceAddress(), 111 mAvrAddress)); 112 } 113 } 114 115 @Override 116 boolean processCommand(HdmiCecMessage cmd) { 117 if (mState != STATE_WAITING_TIMEOUT) { 118 return false; 119 } 120 121 int opcode = cmd.getOpcode(); 122 if (opcode == Constants.MESSAGE_FEATURE_ABORT) { 123 int originalOpcode = cmd.getParams()[0] & 0xFF; 124 if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) { 125 HdmiLogger.debug("Feature aborted for <Report Arc Initiated>"); 126 setArcStatus(false); 127 finish(); 128 return true; 129 } 130 } 131 return false; 132 } 133 134 @Override 135 void handleTimerEvent(int state) { 136 if (mState != state || mState != STATE_WAITING_TIMEOUT) { 137 return; 138 } 139 // Expire timeout for <Feature Abort>. 140 finish(); 141 } 142} 143