HdmiCecMessageBuilder.java revision cd97baf4d08f9a23797eb6a8eb0d57bba1086bec
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;
21
22import java.io.UnsupportedEncodingException;
23import java.util.Arrays;
24
25/**
26 * A helper class to build {@link HdmiCecMessage} from various cec commands.
27 */
28public class HdmiCecMessageBuilder {
29    private static final int OSD_NAME_MAX_LENGTH = 13;
30
31    private HdmiCecMessageBuilder() {}
32
33    /**
34     * Build {@link HdmiCecMessage} from raw data.
35     *
36     * @param src source address of command
37     * @param dest destination address of command
38     * @param body body of message. It includes opcode.
39     * @return newly created {@link HdmiCecMessage}
40     */
41    static HdmiCecMessage of(int src, int dest, byte[] body) {
42        byte opcode = body[0];
43        byte params[] = Arrays.copyOfRange(body, 1, body.length);
44        return new HdmiCecMessage(src, dest, opcode, params);
45    }
46
47    /**
48     * Build <Feature Abort> command. <Feature Abort> consists of
49     * 1 byte original opcode and 1 byte reason fields with basic fields.
50     *
51     * @param src source address of command
52     * @param dest destination address of command
53     * @param originalOpcode original opcode causing feature abort
54     * @param reason reason of feature abort
55     * @return newly created {@link HdmiCecMessage}
56     */
57    static HdmiCecMessage buildFeatureAbortCommand(int src, int dest, int originalOpcode,
58            int reason) {
59        byte[] params = new byte[] {
60                (byte) originalOpcode,
61                (byte) reason,
62        };
63        return buildCommand(src, dest, HdmiCec.MESSAGE_FEATURE_ABORT, params);
64    }
65
66    /**
67     * Build <Give Physical Address> command.
68     *
69     * @param src source address of command
70     * @param dest destination address of command
71     * @return newly created {@link HdmiCecMessage}
72     */
73    static HdmiCecMessage buildGivePhysicalAddress(int src, int dest) {
74        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS);
75    }
76
77    /**
78     * Build <Give Osd Name> command.
79     *
80     * @param src source address of command
81     * @param dest destination address of command
82     * @return newly created {@link HdmiCecMessage}
83     */
84    static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
85        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_OSD_NAME);
86    }
87
88    /**
89     * Build <Give Vendor Id Command> command.
90     *
91     * @param src source address of command
92     * @param dest destination address of command
93     * @return newly created {@link HdmiCecMessage}
94     */
95    static HdmiCecMessage buildGiveDeviceVendorIdCommand(int src, int dest) {
96        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID);
97    }
98
99    /**
100     * Build <Set Menu Language > command.
101     *
102     * <p>This is a broadcast message sent to all devices on the bus.
103     *
104     * @param src source address of command
105     * @param language 3-letter ISO639-2 based language code
106     * @return newly created {@link HdmiCecMessage} if language is valid.
107     *         Otherwise, return null
108     */
109    static HdmiCecMessage buildSetMenuLanguageCommand(int src, String language) {
110        if (language.length() != 3) {
111            return null;
112        }
113        // Hdmi CEC uses lower-cased ISO 639-2 (3 letters code).
114        String normalized = language.toLowerCase();
115        byte[] params = new byte[] {
116                (byte) normalized.charAt(0),
117                (byte) normalized.charAt(1),
118                (byte) normalized.charAt(2),
119        };
120        // <Set Menu Language> is broadcast message.
121        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_MENU_LANGUAGE,
122                params);
123    }
124
125    /**
126     * Build &lt;Set Osd Name &gt; command.
127     *
128     * @param src source address of command
129     * @param name display (OSD) name of device
130     * @return newly created {@link HdmiCecMessage} if valid name. Otherwise,
131     *         return null
132     */
133    static HdmiCecMessage buildSetOsdNameCommand(int src, int dest, String name) {
134        int length = Math.min(name.length(), OSD_NAME_MAX_LENGTH);
135        byte[] params;
136        try {
137            params = name.substring(0, length).getBytes("US-ASCII");
138        } catch (UnsupportedEncodingException e) {
139            return null;
140        }
141        return buildCommand(src, dest, HdmiCec.MESSAGE_SET_OSD_NAME, params);
142    }
143
144    /**
145     * Build &lt;Report Physical Address&gt; command. It has two bytes physical
146     * address and one byte device type as parameter.
147     *
148     * <p>This is a broadcast message sent to all devices on the bus.
149     *
150     * @param src source address of command
151     * @param address physical address of device
152     * @param deviceType type of device
153     * @return newly created {@link HdmiCecMessage}
154     */
155    static HdmiCecMessage buildReportPhysicalAddressCommand(int src, int address, int deviceType) {
156        byte[] params = new byte[] {
157                // Two bytes for physical address
158                (byte) ((address >> 8) & 0xFF),
159                (byte) (address & 0xFF),
160                // One byte device type
161                (byte) deviceType
162        };
163        // <Report Physical Address> is broadcast message.
164        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS,
165                params);
166    }
167
168    /**
169     * Build &lt;Device Vendor Id&gt; command. It has three bytes vendor id as
170     * parameter.
171     *
172     * <p>This is a broadcast message sent to all devices on the bus.
173     *
174     * @param src source address of command
175     * @param vendorId device's vendor id
176     * @return newly created {@link HdmiCecMessage}
177     */
178    static HdmiCecMessage buildDeviceVendorIdCommand(int src, int vendorId) {
179        byte[] params = new byte[] {
180                (byte) ((vendorId >> 16) & 0xFF),
181                (byte) ((vendorId >> 8) & 0xFF),
182                (byte) (vendorId & 0xFF)
183        };
184        // <Device Vendor Id> is broadcast message.
185        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_DEVICE_VENDOR_ID,
186                params);
187    }
188
189    /**
190     * Build &lt;Device Vendor Id&gt; command. It has one byte cec version as parameter.
191     *
192     * @param src source address of command
193     * @param dest destination address of command
194     * @param version version of cec. Use 0x04 for "Version 1.3a" and 0x05 for
195     *                "Version 1.4 or 1.4a or 1.4b
196     * @return newly created {@link HdmiCecMessage}
197     */
198    static HdmiCecMessage buildCecVersion(int src, int dest, int version) {
199        byte[] params = new byte[] {
200                (byte) version
201        };
202        return buildCommand(src, dest, HdmiCec.MESSAGE_CEC_VERSION, params);
203    }
204
205    /**
206     * Build &lt;Request Arc Initiation&gt;
207     *
208     * @param src source address of command
209     * @param dest destination address of command
210     * @return newly created {@link HdmiCecMessage}
211     */
212    static HdmiCecMessage buildRequestArcInitiation(int src, int dest) {
213        return buildCommand(src, dest, HdmiCec.MESSAGE_REQUEST_ARC_INITIATION);
214    }
215
216    /**
217     * Build &lt;Request Arc Termination&gt;
218     *
219     * @param src source address of command
220     * @param dest destination address of command
221     * @return newly created {@link HdmiCecMessage}
222     */
223    static HdmiCecMessage buildRequestArcTermination(int src, int dest) {
224        return buildCommand(src, dest, HdmiCec.MESSAGE_REQUEST_ARC_TERMINATION);
225    }
226
227    /**
228     * Build &lt;Report Arc Initiated&gt;
229     *
230     * @param src source address of command
231     * @param dest destination address of command
232     * @return newly created {@link HdmiCecMessage}
233     */
234    static HdmiCecMessage buildReportArcInitiated(int src, int dest) {
235        return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_ARC_INITIATED);
236    }
237
238    /**
239     * Build &lt;Report Arc Terminated&gt;
240     *
241     * @param src source address of command
242     * @param dest destination address of command
243     * @return newly created {@link HdmiCecMessage}
244     */
245    static HdmiCecMessage buildReportArcTerminated(int src, int dest) {
246        return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_ARC_TERMINATED);
247    }
248
249    /**
250     * Build &lt;Text View On&gt; command.
251     *
252     * @param src source address of command
253     * @param dest destination address of command
254     * @return newly created {@link HdmiCecMessage}
255     */
256    static HdmiCecMessage buildTextViewOn(int src, int dest) {
257        return buildCommand(src, dest, HdmiCec.MESSAGE_TEXT_VIEW_ON);
258    }
259
260    /**
261     * Build &lt;Active Source&gt; command.
262     *
263     * @param src source address of command
264     * @param physicalAddress physical address of the device to become active
265     * @return newly created {@link HdmiCecMessage}
266     */
267    static HdmiCecMessage buildActiveSource(int src, int physicalAddress) {
268        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
269                physicalAddressToParam(physicalAddress));
270    }
271
272    /**
273     * Build &lt;Give Device Power Status&gt; command.
274     *
275     * @param src source address of command
276     * @param dest destination address of command
277     * @return newly created {@link HdmiCecMessage}
278     */
279    static HdmiCecMessage buildGiveDevicePowerStatus(int src, int dest) {
280        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS);
281    }
282
283    /**
284     * Build &lt;System Audio Mode Request&gt; command.
285     *
286     * @param src source address of command
287     * @param avr destination address of command, it should be AVR
288     * @param avrPhysicalAddress physical address of AVR
289     * @param enableSystemAudio whether to enable System Audio Mode or not
290     * @return newly created {@link HdmiCecMessage}
291     */
292    static HdmiCecMessage buildSystemAudioModeRequest(int src, int avr, int avrPhysicalAddress,
293            boolean enableSystemAudio) {
294        if (enableSystemAudio) {
295            return buildCommand(src, avr, HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST,
296                    physicalAddressToParam(avrPhysicalAddress));
297        } else {
298            return buildCommand(src, avr, HdmiCec.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST);
299        }
300    }
301
302    /**
303     * Build &lt;Give Audio Status&gt; command.
304     *
305     * @param src source address of command
306     * @param dest destination address of command
307     * @return newly created {@link HdmiCecMessage}
308     */
309    static HdmiCecMessage buildGiveAudioStatus(int src, int dest) {
310        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_AUDIO_STATUS);
311    }
312
313    /**
314     * Build &lt;User Control Pressed&gt; command.
315     *
316     * @param src source address of command
317     * @param dest destination address of command
318     * @param uiCommand keycode that user pressed
319     * @return newly created {@link HdmiCecMessage}
320     */
321    static HdmiCecMessage buildUserControlPressed(int src, int dest, int uiCommand) {
322        return buildUserControlPressed(src, dest, new byte[] { (byte) uiCommand });
323    }
324
325    /**
326     * Build &lt;User Control Pressed&gt; command.
327     *
328     * @param src source address of command
329     * @param dest destination address of command
330     * @param commandParam uiCommand and the additional parameter
331     * @return newly created {@link HdmiCecMessage}
332     */
333    static HdmiCecMessage buildUserControlPressed(int src, int dest, byte[] commandParam) {
334        return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_PRESSED, commandParam);
335    }
336
337    /**
338     * Build &lt;User Control Released&gt; command.
339     *
340     * @param src source address of command
341     * @param dest destination address of command
342     * @return newly created {@link HdmiCecMessage}
343     */
344    static HdmiCecMessage buildUserControlReleased(int src, int dest) {
345        return buildCommand(src, dest, HdmiCec.MESSAGE_USER_CONTROL_RELEASED);
346    }
347
348    /***** Please ADD new buildXXX() methods above. ******/
349
350    /**
351     * Build a {@link HdmiCecMessage} without extra parameter.
352     *
353     * @param src source address of command
354     * @param dest destination address of command
355     * @param opcode opcode for a message
356     * @return newly created {@link HdmiCecMessage}
357     */
358    private static HdmiCecMessage buildCommand(int src, int dest, int opcode) {
359        return new HdmiCecMessage(src, dest, opcode, HdmiCecMessage.EMPTY_PARAM);
360    }
361
362    /**
363     * Build a {@link HdmiCecMessage} with given values.
364     *
365     * @param src source address of command
366     * @param dest destination address of command
367     * @param opcode opcode for a message
368     * @param params extra parameters for command
369     * @return newly created {@link HdmiCecMessage}
370     */
371    private static HdmiCecMessage buildCommand(int src, int dest, int opcode, byte[] params) {
372        return new HdmiCecMessage(src, dest, opcode, params);
373    }
374
375    private static byte[] physicalAddressToParam(int physicalAddress) {
376        return new byte[] {
377                (byte) (physicalAddress >> 8),
378                (byte) (physicalAddress & 0xFF)
379        };
380    }
381}
382