1 /* 2 * Copyright (C) 2018 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 package com.android.server.hdmi; 17 18 import android.hardware.hdmi.HdmiControlManager; 19 import android.hardware.hdmi.HdmiPortInfo; 20 import android.hardware.tv.cec.V1_0.SendMessageResult; 21 22 import com.android.internal.annotations.VisibleForTesting; 23 import com.android.server.hdmi.HdmiCecController.NativeWrapper; 24 25 import com.google.common.collect.Iterables; 26 27 import java.util.ArrayList; 28 import java.util.Arrays; 29 import java.util.HashMap; 30 import java.util.List; 31 import java.util.Map; 32 33 /** Fake {@link NativeWrapper} for the HDMI CEC HAL, useful for testing. */ 34 final class FakeNativeWrapper implements NativeWrapper { 35 private static final String TAG = "FakeNativeWrapper"; 36 37 private final int[] mPollAddressResponse = 38 new int[] { 39 SendMessageResult.NACK, 40 SendMessageResult.NACK, 41 SendMessageResult.NACK, 42 SendMessageResult.NACK, 43 SendMessageResult.NACK, 44 SendMessageResult.NACK, 45 SendMessageResult.NACK, 46 SendMessageResult.NACK, 47 SendMessageResult.NACK, 48 SendMessageResult.NACK, 49 SendMessageResult.NACK, 50 SendMessageResult.NACK, 51 SendMessageResult.NACK, 52 SendMessageResult.NACK, 53 SendMessageResult.NACK, 54 }; 55 56 private final List<HdmiCecMessage> mResultMessages = new ArrayList<>(); 57 private final Map<Integer, Boolean> mPortConnectionStatus = new HashMap<>(); 58 private final HashMap<Integer, Integer> mMessageSendResult = new HashMap<>(); 59 private int mMyPhysicalAddress = 0; 60 private int mVendorId = 0; 61 private HdmiPortInfo[] mHdmiPortInfo = null; 62 private HdmiCecController.HdmiCecCallback mCallback = null; 63 private int mCecVersion = HdmiControlManager.HDMI_CEC_VERSION_2_0; 64 65 @Override nativeInit()66 public String nativeInit() { 67 return "[class or subclass of IHdmiCec]@Proxy"; 68 } 69 70 @Override setCallback(HdmiCecController.HdmiCecCallback callback)71 public void setCallback(HdmiCecController.HdmiCecCallback callback) { 72 this.mCallback = callback; 73 } 74 75 @Override nativeSendCecCommand( int srcAddress, int dstAddress, byte[] body)76 public int nativeSendCecCommand( 77 int srcAddress, int dstAddress, byte[] body) { 78 if (body.length == 0) { 79 return mPollAddressResponse[dstAddress]; 80 } else { 81 HdmiCecMessage message = HdmiCecMessage.build(srcAddress, dstAddress, body[0], 82 Arrays.copyOfRange(body, 1, body.length)); 83 mResultMessages.add(message); 84 return mMessageSendResult.getOrDefault(message.getOpcode(), SendMessageResult.SUCCESS); 85 } 86 } 87 88 @Override nativeAddLogicalAddress(int logicalAddress)89 public int nativeAddLogicalAddress(int logicalAddress) { 90 return 0; 91 } 92 93 @Override nativeClearLogicalAddress()94 public void nativeClearLogicalAddress() {} 95 96 @Override nativeGetPhysicalAddress()97 public int nativeGetPhysicalAddress() { 98 return mMyPhysicalAddress; 99 } 100 101 @Override nativeGetVersion()102 public int nativeGetVersion() { 103 return mCecVersion; 104 } 105 106 @Override nativeGetVendorId()107 public int nativeGetVendorId() { 108 return mVendorId; 109 } 110 111 @Override nativeGetPortInfos()112 public HdmiPortInfo[] nativeGetPortInfos() { 113 if (mHdmiPortInfo == null) { 114 mHdmiPortInfo = new HdmiPortInfo[1]; 115 mHdmiPortInfo[0] = new HdmiPortInfo.Builder(1, 1, 0x1000) 116 .setCecSupported(true) 117 .setMhlSupported(true) 118 .setArcSupported(true) 119 .build(); 120 } 121 return mHdmiPortInfo; 122 } 123 124 @Override enableWakeupByOtp(boolean enabled)125 public void enableWakeupByOtp(boolean enabled) {} 126 127 @Override enableCec(boolean enabled)128 public void enableCec(boolean enabled) {} 129 130 @Override enableSystemCecControl(boolean enabled)131 public void enableSystemCecControl(boolean enabled) {} 132 133 @Override nativeSetLanguage(String language)134 public void nativeSetLanguage(String language) {} 135 136 @Override nativeEnableAudioReturnChannel(int port, boolean flag)137 public void nativeEnableAudioReturnChannel(int port, boolean flag) {} 138 139 @Override nativeIsConnected(int port)140 public boolean nativeIsConnected(int port) { 141 Boolean isConnected = mPortConnectionStatus.get(port); 142 return isConnected == null ? false : isConnected; 143 } 144 145 @Override nativeSetHpdSignalType(int signal, int portId)146 public void nativeSetHpdSignalType(int signal, int portId) {} 147 148 @Override nativeGetHpdSignalType(int portId)149 public int nativeGetHpdSignalType(int portId) { 150 return Constants.HDMI_HPD_TYPE_PHYSICAL; 151 } 152 setPortConnectionStatus(int port, boolean connected)153 public void setPortConnectionStatus(int port, boolean connected) { 154 mPortConnectionStatus.put(port, connected); 155 } 156 setCecVersion(@dmiControlManager.HdmiCecVersion int cecVersion)157 public void setCecVersion(@HdmiControlManager.HdmiCecVersion int cecVersion) { 158 mCecVersion = cecVersion; 159 } 160 onCecMessage(HdmiCecMessage hdmiCecMessage)161 public void onCecMessage(HdmiCecMessage hdmiCecMessage) { 162 if (mCallback == null) { 163 return; 164 } 165 int source = hdmiCecMessage.getSource(); 166 int destination = hdmiCecMessage.getDestination(); 167 byte[] body = new byte[hdmiCecMessage.getParams().length + 1]; 168 int i = 0; 169 body[i++] = (byte) hdmiCecMessage.getOpcode(); 170 for (byte param : hdmiCecMessage.getParams()) { 171 body[i++] = param; 172 } 173 mCallback.onCecMessage(source, destination, body); 174 } 175 onHotplugEvent(int port, boolean connected)176 public void onHotplugEvent(int port, boolean connected) { 177 if (mCallback == null) { 178 return; 179 } 180 181 mCallback.onHotplugEvent(port, connected); 182 } 183 getResultMessages()184 public List<HdmiCecMessage> getResultMessages() { 185 return new ArrayList<>(mResultMessages); 186 } 187 getOnlyResultMessage()188 public HdmiCecMessage getOnlyResultMessage() throws IllegalArgumentException { 189 return Iterables.getOnlyElement(mResultMessages); 190 } 191 clearResultMessages()192 public void clearResultMessages() { 193 mResultMessages.clear(); 194 } 195 setPollAddressResponse(int logicalAddress, int response)196 public void setPollAddressResponse(int logicalAddress, int response) { 197 mPollAddressResponse[logicalAddress] = response; 198 } 199 setMessageSendResult(int opcode, int result)200 public void setMessageSendResult(int opcode, int result) { 201 mMessageSendResult.put(opcode, result); 202 } 203 204 @VisibleForTesting setVendorId(int vendorId)205 protected void setVendorId(int vendorId) { 206 mVendorId = vendorId; 207 } 208 209 @VisibleForTesting setPhysicalAddress(int physicalAddress)210 protected void setPhysicalAddress(int physicalAddress) { 211 mMyPhysicalAddress = physicalAddress; 212 } 213 214 @VisibleForTesting setPortInfo(HdmiPortInfo[] hdmiPortInfo)215 protected void setPortInfo(HdmiPortInfo[] hdmiPortInfo) { 216 mHdmiPortInfo = new HdmiPortInfo[hdmiPortInfo.length]; 217 System.arraycopy(hdmiPortInfo, 0, mHdmiPortInfo, 0, hdmiPortInfo.length); 218 } 219 } 220