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 com.android.server.hdmi.Constants.AudioCodec;
20 
21 import java.io.UnsupportedEncodingException;
22 
23 /**
24  * A helper class to build {@link HdmiCecMessage} from various cec commands.
25  *
26  * If a message type has its own specific subclass of {@link HdmiCecMessage},
27  * its static factory method is instead declared in that subclass.
28  */
29 public class HdmiCecMessageBuilder {
30     private static final int OSD_NAME_MAX_LENGTH = 14;
31 
HdmiCecMessageBuilder()32     private HdmiCecMessageBuilder() {}
33 
34     /**
35      * Build <Feature Abort> command. <Feature Abort> consists of
36      * 1 byte original opcode and 1 byte reason fields with basic fields.
37      *
38      * @param src source address of command
39      * @param dest destination address of command
40      * @param originalOpcode original opcode causing feature abort
41      * @param reason reason of feature abort
42      * @return newly created {@link HdmiCecMessage}
43      */
buildFeatureAbortCommand(int src, int dest, int originalOpcode, int reason)44     static HdmiCecMessage buildFeatureAbortCommand(int src, int dest, int originalOpcode,
45             int reason) {
46         byte[] params = new byte[] {
47                 (byte) (originalOpcode & 0xFF),
48                 (byte) (reason & 0xFF),
49         };
50         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_FEATURE_ABORT, params);
51     }
52 
53     /**
54      * Build <Give Physical Address> command.
55      *
56      * @param src source address of command
57      * @param dest destination address of command
58      * @return newly created {@link HdmiCecMessage}
59      */
buildGivePhysicalAddress(int src, int dest)60     static HdmiCecMessage buildGivePhysicalAddress(int src, int dest) {
61         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS);
62     }
63 
64     /**
65      * Build <Give Osd Name> command.
66      *
67      * @param src source address of command
68      * @param dest destination address of command
69      * @return newly created {@link HdmiCecMessage}
70      */
buildGiveOsdNameCommand(int src, int dest)71     static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
72         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_OSD_NAME);
73     }
74 
75     /**
76      * Build <Give Vendor Id Command> command.
77      *
78      * @param src source address of command
79      * @param dest destination address of command
80      * @return newly created {@link HdmiCecMessage}
81      */
buildGiveDeviceVendorIdCommand(int src, int dest)82     static HdmiCecMessage buildGiveDeviceVendorIdCommand(int src, int dest) {
83         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID);
84     }
85 
86     /**
87      * Build <Set Menu Language > command.
88      *
89      * <p>This is a broadcast message sent to all devices on the bus.
90      *
91      * @param src source address of command
92      * @param language 3-letter ISO639-2 based language code
93      * @return newly created {@link HdmiCecMessage} if language is valid.
94      *         Otherwise, return null
95      */
buildSetMenuLanguageCommand(int src, String language)96     static HdmiCecMessage buildSetMenuLanguageCommand(int src, String language) {
97         if (language.length() != 3) {
98             return null;
99         }
100         // Hdmi CEC uses lower-cased ISO 639-2 (3 letters code).
101         String normalized = language.toLowerCase();
102         byte[] params = new byte[] {
103                 (byte) (normalized.charAt(0) & 0xFF),
104                 (byte) (normalized.charAt(1) & 0xFF),
105                 (byte) (normalized.charAt(2) & 0xFF),
106         };
107         // <Set Menu Language> is broadcast message.
108         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST,
109                 Constants.MESSAGE_SET_MENU_LANGUAGE, params);
110     }
111 
112     /**
113      * Build &lt;Set Osd Name &gt; command.
114      *
115      * @param src source address of command
116      * @param name display (OSD) name of device
117      * @return newly created {@link HdmiCecMessage} if valid name. Otherwise,
118      *         return null
119      */
buildSetOsdNameCommand(int src, int dest, String name)120     static HdmiCecMessage buildSetOsdNameCommand(int src, int dest, String name) {
121         int length = Math.min(name.length(), OSD_NAME_MAX_LENGTH);
122         byte[] params;
123         try {
124             params = name.substring(0, length).getBytes("US-ASCII");
125         } catch (UnsupportedEncodingException e) {
126             return null;
127         }
128         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_SET_OSD_NAME, params);
129     }
130 
131     /**
132      * Build &lt;Report Physical Address&gt; command. It has two bytes physical
133      * address and one byte device type as parameter.
134      *
135      * <p>This is a broadcast message sent to all devices on the bus.
136      *
137      * @param src source address of command
138      * @param address physical address of device
139      * @param deviceType type of device
140      * @return newly created {@link HdmiCecMessage}
141      */
buildReportPhysicalAddressCommand(int src, int address, int deviceType)142     static HdmiCecMessage buildReportPhysicalAddressCommand(int src, int address, int deviceType) {
143         byte[] params = new byte[] {
144                 // Two bytes for physical address
145                 (byte) ((address >> 8) & 0xFF),
146                 (byte) (address & 0xFF),
147                 // One byte device type
148                 (byte) (deviceType & 0xFF)
149         };
150         // <Report Physical Address> is broadcast message.
151         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST,
152                 Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS, params);
153     }
154 
155     /**
156      * Build &lt;Device Vendor Id&gt; command. It has three bytes vendor id as
157      * parameter.
158      *
159      * <p>This is a broadcast message sent to all devices on the bus.
160      *
161      * @param src source address of command
162      * @param vendorId device's vendor id
163      * @return newly created {@link HdmiCecMessage}
164      */
buildDeviceVendorIdCommand(int src, int vendorId)165     static HdmiCecMessage buildDeviceVendorIdCommand(int src, int vendorId) {
166         byte[] params = new byte[] {
167                 (byte) ((vendorId >> 16) & 0xFF),
168                 (byte) ((vendorId >> 8) & 0xFF),
169                 (byte) (vendorId & 0xFF)
170         };
171         // <Device Vendor Id> is broadcast message.
172         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST,
173                 Constants.MESSAGE_DEVICE_VENDOR_ID, params);
174     }
175 
176     /**
177      * Build &lt;Device Vendor Id&gt; command. It has one byte cec version as parameter.
178      *
179      * @param src source address of command
180      * @param dest destination address of command
181      * @param version version of cec. Use 0x04 for "Version 1.3a" and 0x05 for
182      *                "Version 1.4 or 1.4a or 1.4b
183      * @return newly created {@link HdmiCecMessage}
184      */
buildCecVersion(int src, int dest, int version)185     static HdmiCecMessage buildCecVersion(int src, int dest, int version) {
186         byte[] params = new byte[] {
187                 (byte) (version & 0xFF)
188         };
189         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_CEC_VERSION, params);
190     }
191 
192     /**
193      * Build &lt;Request Arc Initiation&gt;
194      *
195      * @param src source address of command
196      * @param dest destination address of command
197      * @return newly created {@link HdmiCecMessage}
198      */
buildRequestArcInitiation(int src, int dest)199     static HdmiCecMessage buildRequestArcInitiation(int src, int dest) {
200         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REQUEST_ARC_INITIATION);
201     }
202 
203     /**
204      * Build &lt;Initiate Arc&gt;
205      *
206      * @param src source address of command
207      * @param dest destination address of command
208      * @return newly created {@link HdmiCecMessage}
209      */
buildInitiateArc(int src, int dest)210     static HdmiCecMessage buildInitiateArc(int src, int dest) {
211         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_INITIATE_ARC);
212     }
213 
214     /**
215      * Build &lt;Terminate Arc&gt;
216      *
217      * @param src source address of command
218      * @param dest destination address of command
219      * @return newly created {@link HdmiCecMessage}
220      */
buildTerminateArc(int src, int dest)221     static HdmiCecMessage buildTerminateArc(int src, int dest) {
222         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_TERMINATE_ARC);
223     }
224 
225     /**
226      * Build &lt;Request Arc Termination&gt;
227      *
228      * @param src source address of command
229      * @param dest destination address of command
230      * @return newly created {@link HdmiCecMessage}
231      */
buildRequestArcTermination(int src, int dest)232     static HdmiCecMessage buildRequestArcTermination(int src, int dest) {
233         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REQUEST_ARC_TERMINATION);
234     }
235 
236     /**
237      * Build &lt;Report Arc Initiated&gt;
238      *
239      * @param src source address of command
240      * @param dest destination address of command
241      * @return newly created {@link HdmiCecMessage}
242      */
buildReportArcInitiated(int src, int dest)243     static HdmiCecMessage buildReportArcInitiated(int src, int dest) {
244         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REPORT_ARC_INITIATED);
245     }
246 
247     /**
248      * Build &lt;Report Arc Terminated&gt;
249      *
250      * @param src source address of command
251      * @param dest destination address of command
252      * @return newly created {@link HdmiCecMessage}
253      */
buildReportArcTerminated(int src, int dest)254     static HdmiCecMessage buildReportArcTerminated(int src, int dest) {
255         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REPORT_ARC_TERMINATED);
256     }
257 
258 
259     /**
260      * Build &lt;Request Short Audio Descriptor&gt; command.
261      *
262      * @param src source address of command
263      * @param dest destination address of command
264      * @param audioFormats the {@link AudioCodec}s desired
265      * @return newly created {@link HdmiCecMessage}
266      */
buildRequestShortAudioDescriptor(int src, int dest, @AudioCodec int[] audioFormats)267     static HdmiCecMessage buildRequestShortAudioDescriptor(int src, int dest,
268             @AudioCodec int[] audioFormats) {
269         byte[] params = new byte[Math.min(audioFormats.length,4)] ;
270         for (int i = 0; i < params.length ; i++){
271             params[i] = (byte) (audioFormats[i] & 0xff);
272         }
273         return HdmiCecMessage.build(
274                 src, dest, Constants.MESSAGE_REQUEST_SHORT_AUDIO_DESCRIPTOR, params);
275     }
276 
277 
278     /**
279      * Build &lt;Text View On&gt; command.
280      *
281      * @param src source address of command
282      * @param dest destination address of command
283      * @return newly created {@link HdmiCecMessage}
284      */
buildTextViewOn(int src, int dest)285     static HdmiCecMessage buildTextViewOn(int src, int dest) {
286         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_TEXT_VIEW_ON);
287     }
288 
289     /**
290      * Build &lt;Image View On&gt; command.
291      *
292      * @param src source address of command
293      * @param dest destination address of command
294      * @return newly created {@link HdmiCecMessage}
295      */
buildImageViewOn(int src, int dest)296     static HdmiCecMessage buildImageViewOn(int src, int dest) {
297         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_IMAGE_VIEW_ON);
298     }
299 
300     /**
301      * Build &lt;Request Active Source&gt; command.
302      *
303      * @param src source address of command
304      * @return newly created {@link HdmiCecMessage}
305      */
buildRequestActiveSource(int src)306     static HdmiCecMessage buildRequestActiveSource(int src) {
307         return HdmiCecMessage.build(
308                 src, Constants.ADDR_BROADCAST, Constants.MESSAGE_REQUEST_ACTIVE_SOURCE);
309     }
310 
311     /**
312      * Build &lt;Active Source&gt; command.
313      *
314      * @param src source address of command
315      * @param physicalAddress physical address of the device to become active
316      * @return newly created {@link HdmiCecMessage}
317      */
buildActiveSource(int src, int physicalAddress)318     static HdmiCecMessage buildActiveSource(int src, int physicalAddress) {
319         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST, Constants.MESSAGE_ACTIVE_SOURCE,
320                 physicalAddressToParam(physicalAddress));
321     }
322 
323     /**
324      * Build &lt;Inactive Source&gt; command.
325      *
326      * @param src source address of command
327      * @param physicalAddress physical address of the device to become inactive
328      * @return newly created {@link HdmiCecMessage}
329      */
buildInactiveSource(int src, int physicalAddress)330     static HdmiCecMessage buildInactiveSource(int src, int physicalAddress) {
331         return HdmiCecMessage.build(src, Constants.ADDR_TV,
332                 Constants.MESSAGE_INACTIVE_SOURCE, physicalAddressToParam(physicalAddress));
333     }
334 
335     /**
336      * Build &lt;Set Stream Path&gt; command.
337      *
338      * <p>This is a broadcast message sent to all devices on the bus.
339      *
340      * @param src source address of command
341      * @param streamPath physical address of the device to start streaming
342      * @return newly created {@link HdmiCecMessage}
343      */
buildSetStreamPath(int src, int streamPath)344     static HdmiCecMessage buildSetStreamPath(int src, int streamPath) {
345         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST,
346                 Constants.MESSAGE_SET_STREAM_PATH, physicalAddressToParam(streamPath));
347     }
348 
349     /**
350      * Build &lt;Routing Change&gt; command.
351      *
352      * <p>This is a broadcast message sent to all devices on the bus.
353      *
354      * @param src source address of command
355      * @param oldPath physical address of the currently active routing path
356      * @param newPath physical address of the new active routing path
357      * @return newly created {@link HdmiCecMessage}
358      */
buildRoutingChange(int src, int oldPath, int newPath)359     static HdmiCecMessage buildRoutingChange(int src, int oldPath, int newPath) {
360         byte[] param = new byte[] {
361             (byte) ((oldPath >> 8) & 0xFF), (byte) (oldPath & 0xFF),
362             (byte) ((newPath >> 8) & 0xFF), (byte) (newPath & 0xFF)
363         };
364         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST, Constants.MESSAGE_ROUTING_CHANGE,
365                 param);
366     }
367 
368     /**
369      * Build &lt;Routing Information&gt; command.
370      *
371      * <p>This is a broadcast message sent to all devices on the bus.
372      *
373      * @param src source address of command
374      * @param physicalAddress physical address of the new active routing path
375      * @return newly created {@link HdmiCecMessage}
376      */
buildRoutingInformation(int src, int physicalAddress)377     static HdmiCecMessage buildRoutingInformation(int src, int physicalAddress) {
378         return HdmiCecMessage.build(src, Constants.ADDR_BROADCAST,
379             Constants.MESSAGE_ROUTING_INFORMATION, physicalAddressToParam(physicalAddress));
380     }
381 
382     /**
383      * Build &lt;Give Device Power Status&gt; command.
384      *
385      * @param src source address of command
386      * @param dest destination address of command
387      * @return newly created {@link HdmiCecMessage}
388      */
buildGiveDevicePowerStatus(int src, int dest)389     static HdmiCecMessage buildGiveDevicePowerStatus(int src, int dest) {
390         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS);
391     }
392 
393     /**
394      * Build &lt;Report Power Status&gt; command.
395      *
396      * @param src source address of command
397      * @param dest destination address of command
398      * @param powerStatus power status of the device
399      * @return newly created {@link HdmiCecMessage}
400      */
buildReportPowerStatus(int src, int dest, int powerStatus)401     static HdmiCecMessage buildReportPowerStatus(int src, int dest, int powerStatus) {
402         byte[] param = new byte[] {
403                 (byte) (powerStatus & 0xFF)
404         };
405         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REPORT_POWER_STATUS, param);
406     }
407 
408     /**
409      * Build &lt;Report Menu Status&gt; command.
410      *
411      * @param src source address of command
412      * @param dest destination address of command
413      * @param menuStatus menu status of the device
414      * @return newly created {@link HdmiCecMessage}
415      */
buildReportMenuStatus(int src, int dest, int menuStatus)416     static HdmiCecMessage buildReportMenuStatus(int src, int dest, int menuStatus) {
417         byte[] param = new byte[] {
418                 (byte) (menuStatus & 0xFF)
419         };
420         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_MENU_STATUS, param);
421     }
422 
423     /**
424      * Build &lt;System Audio Mode Request&gt; command.
425      *
426      * @param src source address of command
427      * @param avr destination address of command, it should be AVR
428      * @param avrPhysicalAddress physical address of AVR
429      * @param enableSystemAudio whether to enable System Audio Mode or not
430      * @return newly created {@link HdmiCecMessage}
431      */
buildSystemAudioModeRequest(int src, int avr, int avrPhysicalAddress, boolean enableSystemAudio)432     static HdmiCecMessage buildSystemAudioModeRequest(int src, int avr, int avrPhysicalAddress,
433             boolean enableSystemAudio) {
434         if (enableSystemAudio) {
435             return HdmiCecMessage.build(src, avr, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
436                     physicalAddressToParam(avrPhysicalAddress));
437         } else {
438             return HdmiCecMessage.build(src, avr, Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST);
439         }
440     }
441 
442     /**
443      * Build &lt;Set System Audio Mode&gt; command.
444      *
445      * @param src source address of command
446      * @param des destination address of command
447      * @param systemAudioStatus whether to set System Audio Mode on or off
448      * @return newly created {@link HdmiCecMessage}
449      */
buildSetSystemAudioMode(int src, int des, boolean systemAudioStatus)450     static HdmiCecMessage buildSetSystemAudioMode(int src, int des, boolean systemAudioStatus) {
451         return buildCommandWithBooleanParam(src, des, Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE,
452             systemAudioStatus
453         );
454     }
455 
456     /**
457      * Build &lt;Report System Audio Mode&gt; command.
458      *
459      * @param src source address of command
460      * @param des destination address of command
461      * @param systemAudioStatus whether System Audio Mode is on or off
462      * @return newly created {@link HdmiCecMessage}
463      */
buildReportSystemAudioMode(int src, int des, boolean systemAudioStatus)464     static HdmiCecMessage buildReportSystemAudioMode(int src, int des, boolean systemAudioStatus) {
465         return buildCommandWithBooleanParam(src, des, Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS,
466             systemAudioStatus
467         );
468     }
469 
470     /**
471      * Build &lt;Report Short Audio Descriptor&gt; command.
472      *
473      * @param src source address of command
474      * @param des destination address of command
475      * @param sadBytes Short Audio Descriptor in bytes
476      * @return newly created {@link HdmiCecMessage}
477      */
buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes)478     static HdmiCecMessage buildReportShortAudioDescriptor(int src, int des, byte[] sadBytes) {
479         return HdmiCecMessage.build(
480                 src, des, Constants.MESSAGE_REPORT_SHORT_AUDIO_DESCRIPTOR, sadBytes);
481     }
482 
483     /**
484      * Build &lt;Give Audio Status&gt; command.
485      *
486      * @param src source address of command
487      * @param dest destination address of command
488      * @return newly created {@link HdmiCecMessage}
489      */
buildGiveAudioStatus(int src, int dest)490     static HdmiCecMessage buildGiveAudioStatus(int src, int dest) {
491         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_AUDIO_STATUS);
492     }
493 
494     /**
495      * Build &lt;Report Audio Status&gt; command.
496      *
497      * @param src source address of command
498      * @param dest destination address of command
499      * @param volume volume level of current device in param
500      * @param mute mute status of current device in param
501      * @return newly created {@link HdmiCecMessage}
502      */
buildReportAudioStatus(int src, int dest, int volume, boolean mute)503     static HdmiCecMessage buildReportAudioStatus(int src, int dest, int volume, boolean mute) {
504         byte status = (byte) ((byte) (mute ? 1 << 7 : 0) | ((byte) volume & 0x7F));
505         byte[] params = new byte[] { status };
506         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_REPORT_AUDIO_STATUS, params);
507     }
508 
509     /**
510      * Build &lt;User Control Pressed&gt; command.
511      *
512      * @param src source address of command
513      * @param dest destination address of command
514      * @param uiCommand keycode that user pressed
515      * @return newly created {@link HdmiCecMessage}
516      */
buildUserControlPressed(int src, int dest, int uiCommand)517     static HdmiCecMessage buildUserControlPressed(int src, int dest, int uiCommand) {
518         return buildUserControlPressed(src, dest, new byte[] { (byte) (uiCommand & 0xFF) });
519     }
520 
521     /**
522      * Build &lt;User Control Pressed&gt; command.
523      *
524      * @param src source address of command
525      * @param dest destination address of command
526      * @param commandParam uiCommand and the additional parameter
527      * @return newly created {@link HdmiCecMessage}
528      */
buildUserControlPressed(int src, int dest, byte[] commandParam)529     static HdmiCecMessage buildUserControlPressed(int src, int dest, byte[] commandParam) {
530         return HdmiCecMessage.build(
531                 src, dest, Constants.MESSAGE_USER_CONTROL_PRESSED, commandParam);
532     }
533 
534     /**
535      * Build &lt;User Control Released&gt; command.
536      *
537      * @param src source address of command
538      * @param dest destination address of command
539      * @return newly created {@link HdmiCecMessage}
540      */
buildUserControlReleased(int src, int dest)541     static HdmiCecMessage buildUserControlReleased(int src, int dest) {
542         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_USER_CONTROL_RELEASED);
543     }
544 
545     /**
546      * Build &lt;Give System Audio Mode Status&gt; command.
547      *
548      * @param src source address of command
549      * @param dest destination address of command
550      * @return newly created {@link HdmiCecMessage}
551      */
buildGiveSystemAudioModeStatus(int src, int dest)552     static HdmiCecMessage buildGiveSystemAudioModeStatus(int src, int dest) {
553         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_SYSTEM_AUDIO_MODE_STATUS);
554     }
555 
556     /**
557      * Build &lt;Standby&gt; command.
558      *
559      * @param src source address of command
560      * @param dest destination address of command
561      * @return newly created {@link HdmiCecMessage}
562      */
buildStandby(int src, int dest)563     public static HdmiCecMessage buildStandby(int src, int dest) {
564         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_STANDBY);
565     }
566 
567     /**
568      * Build &lt;Vendor Command&gt; command.
569      *
570      * @param src source address of command
571      * @param dest destination address of command
572      * @param params vendor-specific parameters
573      * @return newly created {@link HdmiCecMessage}
574      */
buildVendorCommand(int src, int dest, byte[] params)575     static HdmiCecMessage buildVendorCommand(int src, int dest, byte[] params) {
576         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_VENDOR_COMMAND, params);
577     }
578 
579     /**
580      * Build &lt;Vendor Command With ID&gt; command.
581      *
582      * @param src source address of command
583      * @param dest destination address of command
584      * @param vendorId vendor ID
585      * @param operands vendor-specific parameters
586      * @return newly created {@link HdmiCecMessage}
587      */
buildVendorCommandWithId(int src, int dest, int vendorId, byte[] operands)588     static HdmiCecMessage buildVendorCommandWithId(int src, int dest, int vendorId,
589             byte[] operands) {
590         byte[] params = new byte[operands.length + 3];  // parameter plus len(vendorId)
591         params[0] = (byte) ((vendorId >> 16) & 0xFF);
592         params[1] = (byte) ((vendorId >> 8) & 0xFF);
593         params[2] = (byte) (vendorId & 0xFF);
594         System.arraycopy(operands, 0, params, 3, operands.length);
595         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, params);
596     }
597 
598     /**
599      * Build &lt;Record On&gt; command.
600      *
601      * @param src source address of command
602      * @param dest destination address of command
603      * @param params parameter of command
604      * @return newly created {@link HdmiCecMessage}
605      */
buildRecordOn(int src, int dest, byte[] params)606     static HdmiCecMessage buildRecordOn(int src, int dest, byte[] params) {
607         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_RECORD_ON, params);
608     }
609 
610     /**
611      * Build &lt;Record Off&gt; command.
612      *
613      * @param src source address of command
614      * @param dest destination address of command
615      * @return newly created {@link HdmiCecMessage}
616      */
buildRecordOff(int src, int dest)617     static HdmiCecMessage buildRecordOff(int src, int dest) {
618         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_RECORD_OFF);
619     }
620 
621     /**
622      * Build &lt;Set Digital Timer&gt; command.
623      *
624      * @param src source address of command
625      * @param dest destination address of command
626      * @param params byte array of timing information and digital service information to be recorded
627      * @return newly created {@link HdmiCecMessage}
628      */
buildSetDigitalTimer(int src, int dest, byte[] params)629     static HdmiCecMessage buildSetDigitalTimer(int src, int dest, byte[] params) {
630         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_SET_DIGITAL_TIMER, params);
631     }
632 
633     /**
634      * Build &lt;Set Analogue Timer&gt; command.
635      *
636      * @param src source address of command
637      * @param dest destination address of command
638      * @param params byte array of timing information and analog service information to be recorded
639      * @return newly created {@link HdmiCecMessage}
640      */
buildSetAnalogueTimer(int src, int dest, byte[] params)641     static HdmiCecMessage buildSetAnalogueTimer(int src, int dest, byte[] params) {
642         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_SET_ANALOG_TIMER, params);
643     }
644 
645     /**
646      * Build &lt;Set External Timer&gt; command.
647      *
648      * @param src source address of command
649      * @param dest destination address of command
650      * @param params byte array of timing information and external source information to be recorded
651      * @return newly created {@link HdmiCecMessage}
652      */
buildSetExternalTimer(int src, int dest, byte[] params)653     static HdmiCecMessage buildSetExternalTimer(int src, int dest, byte[] params) {
654         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_SET_EXTERNAL_TIMER, params);
655     }
656 
657     /**
658      * Build &lt;Clear Digital Timer&gt; command.
659      *
660      * @param src source address of command
661      * @param dest destination address of command
662      * @param params byte array of timing information and digital service information to be cleared
663      * @return newly created {@link HdmiCecMessage}
664      */
buildClearDigitalTimer(int src, int dest, byte[] params)665     static HdmiCecMessage buildClearDigitalTimer(int src, int dest, byte[] params) {
666         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_CLEAR_DIGITAL_TIMER, params);
667     }
668 
669     /**
670      * Build &lt;Clear Analog Timer&gt; command.
671      *
672      * @param src source address of command
673      * @param dest destination address of command
674      * @param params byte array of timing information and analog service information to be cleared
675      * @return newly created {@link HdmiCecMessage}
676      */
buildClearAnalogueTimer(int src, int dest, byte[] params)677     static HdmiCecMessage buildClearAnalogueTimer(int src, int dest, byte[] params) {
678         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_CLEAR_ANALOG_TIMER, params);
679     }
680 
681     /**
682      * Build &lt;Clear Digital Timer&gt; command.
683      *
684      * @param src source address of command
685      * @param dest destination address of command
686      * @param params byte array of timing information and external source information to be cleared
687      * @return newly created {@link HdmiCecMessage}
688      */
buildClearExternalTimer(int src, int dest, byte[] params)689     static HdmiCecMessage buildClearExternalTimer(int src, int dest, byte[] params) {
690         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params);
691     }
692 
buildGiveFeatures(int src, int dest)693     static HdmiCecMessage buildGiveFeatures(int src, int dest) {
694         return HdmiCecMessage.build(src, dest, Constants.MESSAGE_GIVE_FEATURES);
695     }
696 
697     /***** Please ADD new buildXXX() methods above. ******/
698 
699     /**
700      * Build a {@link HdmiCecMessage} with a boolean param and other given values.
701      *
702      * @param src source address of command
703      * @param des destination address of command
704      * @param opcode opcode for a message
705      * @param param boolean param for building the command
706      * @return newly created {@link HdmiCecMessage}
707      */
buildCommandWithBooleanParam(int src, int des, int opcode, boolean param)708     private static HdmiCecMessage buildCommandWithBooleanParam(int src, int des,
709         int opcode, boolean param) {
710         byte[] params = new byte[]{
711             param ? (byte) 0b1 : 0b0
712         };
713         return HdmiCecMessage.build(src, des, opcode, params);
714     }
715 
physicalAddressToParam(int physicalAddress)716     private static byte[] physicalAddressToParam(int physicalAddress) {
717         return new byte[] {
718                 (byte) ((physicalAddress >> 8) & 0xFF),
719                 (byte) (physicalAddress & 0xFF)
720         };
721     }
722 }
723