SetArcTransmissionStateAction.java revision d643f764f72efc1e7aa67392bf9ac40720ae14c3
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 verifyAddressType(sourceAddress, HdmiCec.DEVICE_TV); 50 verifyAddressType(avrAddress, HdmiCec.DEVICE_AUDIO_SYSTEM); 51 mAvrAddress = avrAddress; 52 mEnabled = enabled; 53 } 54 55 // TODO: extract it as separate utility class. 56 private static void verifyAddressType(int logicalAddress, int deviceType) { 57 int actualDeviceType = HdmiCec.getTypeFromAddress(logicalAddress); 58 if (actualDeviceType != deviceType) { 59 throw new IllegalArgumentException("Device type missmatch:[Expected:" + deviceType 60 + ", Actual:" + actualDeviceType); 61 } 62 } 63 64 @Override 65 boolean start() { 66 if (mEnabled) { 67 sendReportArcInitiated(); 68 } else { 69 setArcStatus(false); 70 finish(); 71 } 72 return true; 73 } 74 75 private void sendReportArcInitiated() { 76 HdmiCecMessage command = 77 HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress); 78 sendCommand(command, new HdmiControlService.SendMessageCallback() { 79 @Override 80 public void onSendCompleted(int error) { 81 if (error == 0) { 82 // Enable ARC status immediately after sending <Report Arc Initiated>. 83 // If AVR responds with <Feature Abort>, disable ARC status again. 84 // This is different from spec that says that turns ARC status to 85 // "Enabled" if <Report ARC Initiated> is acknowledged and no 86 // <Feature Abort> is received. 87 // But implemented this way to save the time having to wait for 88 // <Feature Abort>. 89 setArcStatus(true); 90 // If succeeds to send <Report ARC Initiated>, wait general timeout 91 // to check whether there is no <Feature Abort> for <Report ARC Initiated>. 92 mState = STATE_WAITING_TIMEOUT; 93 addTimer(mState, TIMEOUT_MS); 94 } else { 95 // If fails to send <Report ARC Initiated>, disable ARC and 96 // send <Report ARC Terminated> directly. 97 Slog.w(TAG, "Failed to send <Report ARC Initiated>:[source:" 98 + mSourceAddress 99 + ", avr Address:" + mAvrAddress + "]"); 100 setArcStatus(false); 101 finish(); 102 } 103 } 104 }); 105 } 106 107 private void setArcStatus(boolean enabled) { 108 boolean wasEnabled = mService.setArcStatus(enabled); 109 Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled); 110 111 // If enabled before and set to "disabled" and send <Report Arc Terminated> to 112 // av reciever. 113 if (!enabled && wasEnabled) { 114 sendCommand( 115 HdmiCecMessageBuilder.buildReportArcTerminated(mSourceAddress, mAvrAddress)); 116 } 117 } 118 119 @Override 120 boolean processCommand(HdmiCecMessage cmd) { 121 if (mState != STATE_WAITING_TIMEOUT) { 122 return false; 123 } 124 125 int opcode = cmd.getOpcode(); 126 if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) { 127 setArcStatus(false); 128 } 129 finish(); 130 return true; 131 } 132 133 @Override 134 void handleTimerEvent(int state) { 135 if (mState != state || mState != STATE_WAITING_TIMEOUT) { 136 return; 137 } 138 // Expire timeout for <Feature Abort>. 139 finish(); 140 } 141} 142