HdmiCecMessageBuilder.java revision d42a7a322b7adf532ae0b70cb9eb1df7e62a8f2d
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    // TODO: move these values to HdmiCec.java once make it internal constant class.
30    // CEC's ABORT reason values.
31    static final int ABORT_UNRECOGNIZED_MODE = 0;
32    static final int ABORT_NOT_IN_CORRECT_MODE = 1;
33    static final int ABORT_CANNOT_PROVIDE_SOURCE = 2;
34    static final int ABORT_INVALID_OPERAND = 3;
35    static final int ABORT_REFUSED = 4;
36    static final int ABORT_UNABLE_TO_DETERMINE = 5;
37
38    private static final int OSD_NAME_MAX_LENGTH = 13;
39
40    private HdmiCecMessageBuilder() {}
41
42    /**
43     * Build {@link HdmiCecMessage} from raw data.
44     *
45     * @param src source address of command
46     * @param dest destination address of command
47     * @param body body of message. It includes opcode.
48     * @return newly created {@link HdmiCecMessage}
49     */
50    static HdmiCecMessage of(int src, int dest, byte[] body) {
51        byte opcode = body[0];
52        byte params[] = Arrays.copyOfRange(body, 1, body.length);
53        return new HdmiCecMessage(src, dest, opcode, params);
54    }
55
56    /**
57     * Build <Feature Abort> command. <Feature Abort> consists of
58     * 1 byte original opcode and 1 byte reason fields with basic fields.
59     *
60     * @param src source address of command
61     * @param dest destination address of command
62     * @param originalOpcode original opcode causing feature abort
63     * @param reason reason of feature abort
64     * @return newly created {@link HdmiCecMessage}
65     */
66    static HdmiCecMessage buildFeatureAbortCommand(int src, int dest, int originalOpcode,
67            int reason) {
68        byte[] params = new byte[] {
69                (byte) originalOpcode,
70                (byte) reason,
71        };
72        return buildCommand(src, dest, HdmiCec.MESSAGE_FEATURE_ABORT, params);
73    }
74
75    /**
76     * Build <Give Physical Address> command.
77     *
78     * @param src source address of command
79     * @param dest destination address of command
80     * @return newly created {@link HdmiCecMessage}
81     */
82    static HdmiCecMessage buildGivePhysicalAddress(int src, int dest) {
83        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_PHYSICAL_ADDRESS);
84    }
85
86    /**
87     * Build <Give Osd Name> command.
88     *
89     * @param src source address of command
90     * @param dest destination address of command
91     * @return newly created {@link HdmiCecMessage}
92     */
93    static HdmiCecMessage buildGiveOsdNameCommand(int src, int dest) {
94        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_OSD_NAME);
95    }
96
97    /**
98     * Build <Give Vendor Id Command> command.
99     *
100     * @param src source address of command
101     * @param dest destination address of command
102     * @return newly created {@link HdmiCecMessage}
103     */
104    static HdmiCecMessage buildGiveDeviceVendorIdCommand(int src, int dest) {
105        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_VENDOR_ID);
106    }
107
108    /**
109     * Build <Set Menu Language > command.
110     *
111     * <p>This is a broadcast message sent to all devices on the bus.
112     *
113     * @param src source address of command
114     * @param language 3-letter ISO639-2 based language code
115     * @return newly created {@link HdmiCecMessage} if language is valid.
116     *         Otherwise, return null
117     */
118    static HdmiCecMessage buildSetMenuLanguageCommand(int src, String language) {
119        if (language.length() != 3) {
120            return null;
121        }
122        // Hdmi CEC uses lower-cased ISO 639-2 (3 letters code).
123        String normalized = language.toLowerCase();
124        byte[] params = new byte[] {
125                (byte) normalized.charAt(0),
126                (byte) normalized.charAt(1),
127                (byte) normalized.charAt(2),
128        };
129        // <Set Menu Language> is broadcast message.
130        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_SET_MENU_LANGUAGE,
131                params);
132    }
133
134    /**
135     * Build &lt;Set Osd Name &gt; command.
136     *
137     * @param src source address of command
138     * @param name display (OSD) name of device
139     * @return newly created {@link HdmiCecMessage} if valid name. Otherwise,
140     *         return null
141     */
142    static HdmiCecMessage buildSetOsdNameCommand(int src, int dest, String name) {
143        int length = Math.min(name.length(), OSD_NAME_MAX_LENGTH);
144        byte[] params;
145        try {
146            params = name.substring(0, length).getBytes("US-ASCII");
147        } catch (UnsupportedEncodingException e) {
148            return null;
149        }
150        return buildCommand(src, dest, HdmiCec.MESSAGE_SET_OSD_NAME, params);
151    }
152
153    /**
154     * Build &lt;Report Physical Address&gt; command. It has two bytes physical
155     * address and one byte device type as parameter.
156     *
157     * <p>This is a broadcast message sent to all devices on the bus.
158     *
159     * @param src source address of command
160     * @param address physical address of device
161     * @param deviceType type of device
162     * @return newly created {@link HdmiCecMessage}
163     */
164    static HdmiCecMessage buildReportPhysicalAddressCommand(int src, int address, int deviceType) {
165        byte[] params = new byte[] {
166                // Two bytes for physical address
167                (byte) ((address >> 8) & 0xFF),
168                (byte) (address & 0xFF),
169                // One byte device type
170                (byte) deviceType
171        };
172        // <Report Physical Address> is broadcast message.
173        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS,
174                params);
175    }
176
177    /**
178     * Build &lt;Device Vendor Id&gt; command. It has three bytes vendor id as
179     * parameter.
180     *
181     * <p>This is a broadcast message sent to all devices on the bus.
182     *
183     * @param src source address of command
184     * @param vendorId device's vendor id
185     * @return newly created {@link HdmiCecMessage}
186     */
187    static HdmiCecMessage buildDeviceVendorIdCommand(int src, int vendorId) {
188        byte[] params = new byte[] {
189                (byte) ((vendorId >> 16) & 0xFF),
190                (byte) ((vendorId >> 8) & 0xFF),
191                (byte) (vendorId & 0xFF)
192        };
193        // <Device Vendor Id> is broadcast message.
194        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_DEVICE_VENDOR_ID,
195                params);
196    }
197
198    /**
199     * Build &lt;Device Vendor Id&gt; command. It has one byte cec version as parameter.
200     *
201     * @param src source address of command
202     * @param dest destination address of command
203     * @param version version of cec. Use 0x04 for "Version 1.3a" and 0x05 for
204     *                "Version 1.4 or 1.4a or 1.4b
205     * @return newly created {@link HdmiCecMessage}
206     */
207    static HdmiCecMessage buildCecVersion(int src, int dest, int version) {
208        byte[] params = new byte[] {
209                (byte) version
210        };
211        return buildCommand(src, dest, HdmiCec.MESSAGE_CEC_VERSION, params);
212    }
213
214    /**
215     * Build &lt;Request Arc Initiation&gt;
216     *
217     * @param src source address of command
218     * @param dest destination address of command
219     * @return newly created {@link HdmiCecMessage}
220     */
221    static HdmiCecMessage buildRequestArcInitiation(int src, int dest) {
222        return buildCommand(src, dest, HdmiCec.MESSAGE_REQUEST_ARC_INITIATION);
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     */
232    static HdmiCecMessage buildRequestArcTermination(int src, int dest) {
233        return buildCommand(src, dest, HdmiCec.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     */
243    static HdmiCecMessage buildReportArcInitiated(int src, int dest) {
244        return buildCommand(src, dest, HdmiCec.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     */
254    static HdmiCecMessage buildReportArcTerminated(int src, int dest) {
255        return buildCommand(src, dest, HdmiCec.MESSAGE_REPORT_ARC_TERMINATED);
256    }
257
258    /**
259     * Build &lt;Text View On&gt; command.
260     *
261     * @param src source address of command
262     * @param dest destination address of command
263     * @return newly created {@link HdmiCecMessage}
264     */
265    static HdmiCecMessage buildTextViewOn(int src, int dest) {
266        return buildCommand(src, dest, HdmiCec.MESSAGE_TEXT_VIEW_ON);
267    }
268
269    /**
270     * Build &lt;Active Source&gt; command.
271     *
272     * @param src source address of command
273     * @param physicalAddress physical address of the device to become active
274     * @return newly created {@link HdmiCecMessage}
275     */
276    static HdmiCecMessage buildActiveSource(int src, int physicalAddress) {
277        return buildCommand(src, HdmiCec.ADDR_BROADCAST, HdmiCec.MESSAGE_ACTIVE_SOURCE,
278                physicalAddressToParam(physicalAddress));
279    }
280
281    /**
282     * Build &lt;Give Device Power Status&gt; command.
283     *
284     * @param src source address of command
285     * @param dest destination address of command
286     * @return newly created {@link HdmiCecMessage}
287     */
288    static HdmiCecMessage buildGiveDevicePowerStatus(int src, int dest) {
289        return buildCommand(src, dest, HdmiCec.MESSAGE_GIVE_DEVICE_POWER_STATUS);
290    }
291
292    /**
293     * Build a {@link HdmiCecMessage} without extra parameter.
294     *
295     * @param src source address of command
296     * @param dest destination address of command
297     * @param opcode opcode for a message
298     * @return newly created {@link HdmiCecMessage}
299     */
300    private static HdmiCecMessage buildCommand(int src, int dest, int opcode) {
301        return new HdmiCecMessage(src, dest, opcode, HdmiCecMessage.EMPTY_PARAM);
302    }
303
304    /**
305     * Build a {@link HdmiCecMessage} with given values.
306     *
307     * @param src source address of command
308     * @param dest destination address of command
309     * @param opcode opcode for a message
310     * @param params extra parameters for command
311     * @return newly created {@link HdmiCecMessage}
312     */
313    private static HdmiCecMessage buildCommand(int src, int dest, int opcode, byte[] params) {
314        return new HdmiCecMessage(src, dest, opcode, params);
315    }
316
317    private static byte[] physicalAddressToParam(int physicalAddress) {
318        return new byte[] {
319                (byte) (physicalAddress >> 8),
320                (byte) (physicalAddress & 0xFF)
321        };
322    }
323}
324