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.annotation.Nullable;
20 
21 import libcore.util.EmptyArray;
22 
23 import java.util.Arrays;
24 import java.util.Objects;
25 
26 /**
27  * A class to encapsulate HDMI-CEC message used for the devices connected via
28  * HDMI cable to communicate with one another. A message is defined by its
29  * source and destination address, command (or opcode), and optional parameters.
30  */
31 public final class HdmiCecMessage {
32     public static final byte[] EMPTY_PARAM = EmptyArray.BYTE;
33 
34     private final int mSource;
35     private final int mDestination;
36 
37     private final int mOpcode;
38     private final byte[] mParams;
39 
40     /**
41      * Constructor.
42      */
HdmiCecMessage(int source, int destination, int opcode, byte[] params)43     public HdmiCecMessage(int source, int destination, int opcode, byte[] params) {
44         mSource = source;
45         mDestination = destination;
46         mOpcode = opcode & 0xFF;
47         mParams = Arrays.copyOf(params, params.length);
48     }
49 
50     @Override
equals(@ullable Object message)51     public boolean equals(@Nullable Object message) {
52         if (message instanceof HdmiCecMessage) {
53             HdmiCecMessage that = (HdmiCecMessage) message;
54             return this.mSource == that.getSource() &&
55                 this.mDestination == that.getDestination() &&
56                 this.mOpcode == that.getOpcode() &&
57                 Arrays.equals(this.mParams, that.getParams());
58         }
59         return false;
60     }
61 
62     @Override
hashCode()63     public int hashCode() {
64         return Objects.hash(
65             mSource,
66             mDestination,
67             mOpcode,
68             Arrays.hashCode(mParams));
69     }
70 
71     /**
72      * Return the source address field of the message. It is the logical address
73      * of the device which generated the message.
74      *
75      * @return source address
76      */
getSource()77     public int getSource() {
78         return mSource;
79     }
80 
81     /**
82      * Return the destination address field of the message. It is the logical address
83      * of the device to which the message is sent.
84      *
85      * @return destination address
86      */
getDestination()87     public int getDestination() {
88         return mDestination;
89     }
90 
91     /**
92      * Return the opcode field of the message. It is the type of the message that
93      * tells the destination device what to do.
94      *
95      * @return opcode
96      */
getOpcode()97     public int getOpcode() {
98         return mOpcode;
99     }
100 
101     /**
102      * Return the parameter field of the message. The contents of parameter varies
103      * from opcode to opcode, and is used together with opcode to describe
104      * the action for the destination device to take.
105      *
106      * @return parameter
107      */
getParams()108     public byte[] getParams() {
109         return mParams;
110     }
111 
112     @Override
toString()113     public String toString() {
114         StringBuffer s = new StringBuffer();
115         s.append(String.format("<%s> %X%X:%02X",
116                 opcodeToString(mOpcode), mSource, mDestination, mOpcode));
117         if (mParams.length > 0) {
118             if (filterMessageParameters(mOpcode)) {
119                 s.append(String.format(" <Redacted len=%d>", mParams.length));
120             } else {
121                 for (byte data : mParams) {
122                     s.append(String.format(":%02X", data));
123                 }
124             }
125         }
126         return s.toString();
127     }
128 
opcodeToString(int opcode)129     private static String opcodeToString(int opcode) {
130         switch (opcode) {
131             case Constants.MESSAGE_FEATURE_ABORT:
132                 return "Feature Abort";
133             case Constants.MESSAGE_IMAGE_VIEW_ON:
134                 return "Image View On";
135             case Constants.MESSAGE_TUNER_STEP_INCREMENT:
136                 return "Tuner Step Increment";
137             case Constants.MESSAGE_TUNER_STEP_DECREMENT:
138                 return "Tuner Step Decrement";
139             case Constants.MESSAGE_TUNER_DEVICE_STATUS:
140                 return "Tuner Device Status";
141             case Constants.MESSAGE_GIVE_TUNER_DEVICE_STATUS:
142                 return "Give Tuner Device Status";
143             case Constants.MESSAGE_RECORD_ON:
144                 return "Record On";
145             case Constants.MESSAGE_RECORD_STATUS:
146                 return "Record Status";
147             case Constants.MESSAGE_RECORD_OFF:
148                 return "Record Off";
149             case Constants.MESSAGE_TEXT_VIEW_ON:
150                 return "Text View On";
151             case Constants.MESSAGE_RECORD_TV_SCREEN:
152                 return "Record Tv Screen";
153             case Constants.MESSAGE_GIVE_DECK_STATUS:
154                 return "Give Deck Status";
155             case Constants.MESSAGE_DECK_STATUS:
156                 return "Deck Status";
157             case Constants.MESSAGE_SET_MENU_LANGUAGE:
158                 return "Set Menu Language";
159             case Constants.MESSAGE_CLEAR_ANALOG_TIMER:
160                 return "Clear Analog Timer";
161             case Constants.MESSAGE_SET_ANALOG_TIMER:
162                 return "Set Analog Timer";
163             case Constants.MESSAGE_TIMER_STATUS:
164                 return "Timer Status";
165             case Constants.MESSAGE_STANDBY:
166                 return "Standby";
167             case Constants.MESSAGE_PLAY:
168                 return "Play";
169             case Constants.MESSAGE_DECK_CONTROL:
170                 return "Deck Control";
171             case Constants.MESSAGE_TIMER_CLEARED_STATUS:
172                 return "Timer Cleared Status";
173             case Constants.MESSAGE_USER_CONTROL_PRESSED:
174                 return "User Control Pressed";
175             case Constants.MESSAGE_USER_CONTROL_RELEASED:
176                 return "User Control Release";
177             case Constants.MESSAGE_GIVE_OSD_NAME:
178                 return "Give Osd Name";
179             case Constants.MESSAGE_SET_OSD_NAME:
180                 return "Set Osd Name";
181             case Constants.MESSAGE_SET_OSD_STRING:
182                 return "Set Osd String";
183             case Constants.MESSAGE_SET_TIMER_PROGRAM_TITLE:
184                 return "Set Timer Program Title";
185             case Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST:
186                 return "System Audio Mode Request";
187             case Constants.MESSAGE_GIVE_AUDIO_STATUS:
188                 return "Give Audio Status";
189             case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE:
190                 return "Set System Audio Mode";
191             case Constants.MESSAGE_REPORT_AUDIO_STATUS:
192                 return "Report Audio Status";
193             case Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS:
194                 return "Give System Audio Mode Status";
195             case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS:
196                 return "System Audio Mode Status";
197             case Constants.MESSAGE_ROUTING_CHANGE:
198                 return "Routing Change";
199             case Constants.MESSAGE_ROUTING_INFORMATION:
200                 return "Routing Information";
201             case Constants.MESSAGE_ACTIVE_SOURCE:
202                 return "Active Source";
203             case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
204                 return "Give Physical Address";
205             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
206                 return "Report Physical Address";
207             case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE:
208                 return "Request Active Source";
209             case Constants.MESSAGE_SET_STREAM_PATH:
210                 return "Set Stream Path";
211             case Constants.MESSAGE_DEVICE_VENDOR_ID:
212                 return "Device Vendor Id";
213             case Constants.MESSAGE_VENDOR_COMMAND:
214                 return "Vendor Command";
215             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
216                 return "Vendor Remote Button Down";
217             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
218                 return "Vendor Remote Button Up";
219             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
220                 return "Give Device Vendor Id";
221             case Constants.MESSAGE_MENU_REQUEST:
222                 return "Menu Request";
223             case Constants.MESSAGE_MENU_STATUS:
224                 return "Menu Status";
225             case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
226                 return "Give Device Power Status";
227             case Constants.MESSAGE_REPORT_POWER_STATUS:
228                 return "Report Power Status";
229             case Constants.MESSAGE_GET_MENU_LANGUAGE:
230                 return "Get Menu Language";
231             case Constants.MESSAGE_SELECT_ANALOG_SERVICE:
232                 return "Select Analog Service";
233             case Constants.MESSAGE_SELECT_DIGITAL_SERVICE:
234                 return "Select Digital Service";
235             case Constants.MESSAGE_SET_DIGITAL_TIMER:
236                 return "Set Digital Timer";
237             case Constants.MESSAGE_CLEAR_DIGITAL_TIMER:
238                 return "Clear Digital Timer";
239             case Constants.MESSAGE_SET_AUDIO_RATE:
240                 return "Set Audio Rate";
241             case Constants.MESSAGE_INACTIVE_SOURCE:
242                 return "InActive Source";
243             case Constants.MESSAGE_CEC_VERSION:
244                 return "Cec Version";
245             case Constants.MESSAGE_GET_CEC_VERSION:
246                 return "Get Cec Version";
247             case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
248                 return "Vendor Command With Id";
249             case Constants.MESSAGE_CLEAR_EXTERNAL_TIMER:
250                 return "Clear External Timer";
251             case Constants.MESSAGE_SET_EXTERNAL_TIMER:
252                 return "Set External Timer";
253             case Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR:
254                 return "Report Short Audio Descriptor";
255             case Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR:
256                 return "Request Short Audio Descriptor";
257             case Constants.MESSAGE_INITIATE_ARC:
258                 return "Initiate ARC";
259             case Constants.MESSAGE_REPORT_ARC_INITIATED:
260                 return "Report ARC Initiated";
261             case Constants.MESSAGE_REPORT_ARC_TERMINATED:
262                 return "Report ARC Terminated";
263             case Constants.MESSAGE_REQUEST_ARC_INITIATION:
264                 return "Request ARC Initiation";
265             case Constants.MESSAGE_REQUEST_ARC_TERMINATION:
266                 return "Request ARC Termination";
267             case Constants.MESSAGE_TERMINATE_ARC:
268                 return "Terminate ARC";
269             case Constants.MESSAGE_CDC_MESSAGE:
270                 return "Cdc Message";
271             case Constants.MESSAGE_ABORT:
272                 return "Abort";
273             default:
274                 return String.format("Opcode: %02X", opcode);
275         }
276     }
277 
filterMessageParameters(int opcode)278     private static boolean filterMessageParameters(int opcode) {
279         switch (opcode) {
280             case Constants.MESSAGE_USER_CONTROL_PRESSED:
281             case Constants.MESSAGE_USER_CONTROL_RELEASED:
282             case Constants.MESSAGE_SET_OSD_NAME:
283             case Constants.MESSAGE_SET_OSD_STRING:
284             case Constants.MESSAGE_VENDOR_COMMAND:
285             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_DOWN:
286             case Constants.MESSAGE_VENDOR_REMOTE_BUTTON_UP:
287             case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
288                 return true;
289             default:
290                 return false;
291         }
292     }
293 }
294 
295