HdmiCecMessageBuilder.java revision 12e5dcefe136b58562f39604e6a8460ac92cb895
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_TV, 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 /** 428 * Build <Vendor Command> command. 429 * 430 * @param src source address of command 431 * @param dest destination address of command 432 * @param params vendor-specific parameters 433 * @return newly created {@link HdmiCecMessage} 434 */ 435 static HdmiCecMessage buildVendorCommand(int src, int dest, byte[] params) { 436 return buildCommand(src, dest, Constants.MESSAGE_VENDOR_COMMAND, params); 437 } 438 439 /** 440 * Build <Vendor Command With ID> command. 441 * 442 * @param src source address of command 443 * @param dest destination address of command 444 * @param vendorId vendor ID 445 * @param operands vendor-specific parameters 446 * @return newly created {@link HdmiCecMessage} 447 */ 448 static HdmiCecMessage buildVendorCommandWithId(int src, int dest, int vendorId, 449 byte[] operands) { 450 byte[] params = new byte[operands.length + 3]; // parameter plus len(vendorId) 451 params[0] = (byte) ((vendorId >> 16) & 0xFF); 452 params[1] = (byte) ((vendorId >> 8) & 0xFF); 453 params[2] = (byte) (vendorId & 0xFF); 454 System.arraycopy(operands, 0, params, 3, operands.length); 455 return buildCommand(src, dest, Constants.MESSAGE_VENDOR_COMMAND_WITH_ID, params); 456 } 457 458 /** 459 * Build <Record On> command. 460 * 461 * @param src source address of command 462 * @param dest destination address of command 463 * @param params parameter of command 464 * @return newly created {@link HdmiCecMessage} 465 */ 466 static HdmiCecMessage buildRecordOn(int src, int dest, byte[] params) { 467 return buildCommand(src, dest, Constants.MESSAGE_RECORD_ON, params); 468 } 469 470 /** 471 * Build <Record Off> command. 472 * 473 * @param src source address of command 474 * @param dest destination address of command 475 * @return newly created {@link HdmiCecMessage} 476 */ 477 static HdmiCecMessage buildRecordOff(int src, int dest) { 478 return buildCommand(src, dest, Constants.MESSAGE_RECORD_OFF); 479 } 480 481 /** 482 * Build <Set Digital Timer> command. 483 * 484 * @param src source address of command 485 * @param dest destination address of command 486 * @param params byte array of timing information and digital service information to be recorded 487 * @return newly created {@link HdmiCecMessage} 488 */ 489 static HdmiCecMessage buildSetDigitalTimer(int src, int dest, byte[] params) { 490 return buildCommand(src, dest, Constants.MESSAGE_SET_DIGITAL_TIMER, params); 491 } 492 493 /** 494 * Build <Set Analogue Timer> command. 495 * 496 * @param src source address of command 497 * @param dest destination address of command 498 * @param params byte array of timing information and analog service information to be recorded 499 * @return newly created {@link HdmiCecMessage} 500 */ 501 static HdmiCecMessage buildSetAnalogueTimer(int src, int dest, byte[] params) { 502 return buildCommand(src, dest, Constants.MESSAGE_SET_ANALOG_TIMER, params); 503 } 504 505 /** 506 * Build <Set External Timer> command. 507 * 508 * @param src source address of command 509 * @param dest destination address of command 510 * @param params byte array of timing information and external source information to be recorded 511 * @return newly created {@link HdmiCecMessage} 512 */ 513 static HdmiCecMessage buildSetExternalTimer(int src, int dest, byte[] params) { 514 return buildCommand(src, dest, Constants.MESSAGE_SET_EXTERNAL_TIMER, params); 515 } 516 517 /** 518 * Build <Clear Digital Timer> command. 519 * 520 * @param src source address of command 521 * @param dest destination address of command 522 * @param params byte array of timing information and digital service information to be cleared 523 * @return newly created {@link HdmiCecMessage} 524 */ 525 static HdmiCecMessage buildClearDigitalTimer(int src, int dest, byte[] params) { 526 return buildCommand(src, dest, Constants.MESSAGE_CLEAR_DIGITAL_TIMER, params); 527 } 528 529 /** 530 * Build <Clear Analog Timer> command. 531 * 532 * @param src source address of command 533 * @param dest destination address of command 534 * @param params byte array of timing information and analog service information to be cleared 535 * @return newly created {@link HdmiCecMessage} 536 */ 537 static HdmiCecMessage buildClearAnalogueTimer(int src, int dest, byte[] params) { 538 return buildCommand(src, dest, Constants.MESSAGE_CLEAR_ANALOG_TIMER, params); 539 } 540 541 /** 542 * Build <Clear Digital Timer> command. 543 * 544 * @param src source address of command 545 * @param dest destination address of command 546 * @param params byte array of timing information and external source information to be cleared 547 * @return newly created {@link HdmiCecMessage} 548 */ 549 static HdmiCecMessage buildClearExternalTimer(int src, int dest, byte[] params) { 550 return buildCommand(src, dest, Constants.MESSAGE_CLEAR_EXTERNAL_TIMER, params); 551 } 552 553 /***** Please ADD new buildXXX() methods above. ******/ 554 555 /** 556 * Build a {@link HdmiCecMessage} without extra parameter. 557 * 558 * @param src source address of command 559 * @param dest destination address of command 560 * @param opcode opcode for a message 561 * @return newly created {@link HdmiCecMessage} 562 */ 563 private static HdmiCecMessage buildCommand(int src, int dest, int opcode) { 564 return new HdmiCecMessage(src, dest, opcode, HdmiCecMessage.EMPTY_PARAM); 565 } 566 567 /** 568 * Build a {@link HdmiCecMessage} with given values. 569 * 570 * @param src source address of command 571 * @param dest destination address of command 572 * @param opcode opcode for a message 573 * @param params extra parameters for command 574 * @return newly created {@link HdmiCecMessage} 575 */ 576 private static HdmiCecMessage buildCommand(int src, int dest, int opcode, byte[] params) { 577 return new HdmiCecMessage(src, dest, opcode, params); 578 } 579 580 private static byte[] physicalAddressToParam(int physicalAddress) { 581 return new byte[] { 582 (byte) (physicalAddress >> 8), 583 (byte) (physicalAddress & 0xFF) 584 }; 585 } 586} 587