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