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 <Set Osd Name > 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 <Report Physical Address> 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 <Device Vendor Id> 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 <Device Vendor Id> 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 <Request Arc Initiation> 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 <Request Arc Termination> 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 <Report Arc Initiated> 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 <Report Arc Terminated> 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 <Text View On> 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 <Active Source> 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 <Give Device Power Status> 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 <System Audio Mode Request> 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 <Give Audio Status> 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 <User Control Pressed> 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 <User Control Pressed> 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 <User Control Released> 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