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