HdmiCecMessageBuilder.java revision cc5ef8c918e96516a5c51cc40735a1b8a24d8497
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 <Set Osd Name > 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 <Report Physical Address> 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 <Device Vendor Id> 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 <Device Vendor Id> 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 <Request Arc Initiation> 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 <Request Arc Termination> 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 <Report Arc Initiated> 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 <Report Arc Terminated> 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 <Text View On> 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 <Active Source> 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 <Give Device Power Status> 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