NewDeviceAction.java revision a466929979a92a578d4ba00093fefa57cfb982b4
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 */ 16package com.android.server.hdmi; 17 18import android.hardware.hdmi.HdmiCec; 19import android.hardware.hdmi.HdmiCecDeviceInfo; 20import android.hardware.hdmi.HdmiCecMessage; 21import android.util.Slog; 22 23import java.io.UnsupportedEncodingException; 24 25/** 26 * Feature action that discovers the information of a newly found logical device. 27 * 28 * This action is created when receiving <Report Physical Address>, a CEC command a newly 29 * connected HDMI-CEC device broadcasts to announce its advent. Additional commands are issued in 30 * this action to gather more information on the device such as OSD name and device vendor ID. 31 * 32 * <p>The result is made in the form of {@link HdmiCecDeviceInfo} object, and passed to service 33 * for the management through its life cycle. 34 * 35 * <p>Package-private, accessed by {@link HdmiControlService} only. 36 */ 37final class NewDeviceAction extends FeatureAction { 38 39 private static final String TAG = "NewDeviceAction"; 40 41 // State in which the action sent <Give OSD Name> and is waiting for <Set OSD Name> 42 // that contains the name of the device for display on screen. 43 static final int STATE_WAITING_FOR_SET_OSD_NAME = 1; 44 45 // State in which the action sent <Give Device Vendor ID> and is waiting for 46 // <Device Vendor ID> that contains the vendor ID of the device. 47 static final int STATE_WAITING_FOR_DEVICE_VENDOR_ID = 2; 48 49 private final int mDeviceLogicalAddress; 50 private final int mDevicePhysicalAddress; 51 52 private int mVendorId; 53 private String mDisplayName; 54 55 /** 56 * Constructor. 57 * 58 * @param service {@link HdmiControlService} instance 59 * @param sourceAddress logical address to be used as source address 60 * @param deviceLogicalAddress logical address of the device in interest 61 * @param devicePhysicalAddress physical address of the device in interest 62 */ 63 NewDeviceAction(HdmiControlService service, int sourceAddress, int deviceLogicalAddress, 64 int devicePhysicalAddress) { 65 super(service, sourceAddress); 66 mDeviceLogicalAddress = deviceLogicalAddress; 67 mDevicePhysicalAddress = devicePhysicalAddress; 68 mVendorId = HdmiCec.UNKNOWN_VENDOR_ID; 69 } 70 71 @Override 72 public boolean start() { 73 mState = STATE_WAITING_FOR_SET_OSD_NAME; 74 if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_SET_OSD_NAME)) { 75 return true; 76 } 77 78 sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(mSourceAddress, 79 mDeviceLogicalAddress)); 80 addTimer(mState, TIMEOUT_MS); 81 return true; 82 } 83 84 @Override 85 public boolean processCommand(HdmiCecMessage cmd) { 86 // For the logical device in interest, we want two more pieces of information - 87 // osd name and vendor id. They are requested in sequence. In case we don't 88 // get the expected responses (either by timeout or by receiving <feature abort> command), 89 // set them to a default osd name and unknown vendor id respectively. 90 int opcode = cmd.getOpcode(); 91 int src = cmd.getSource(); 92 byte[] params = cmd.getParams(); 93 94 if (mDeviceLogicalAddress != src) { 95 return false; 96 } 97 98 if (mState == STATE_WAITING_FOR_SET_OSD_NAME) { 99 if (opcode == HdmiCec.MESSAGE_SET_OSD_NAME) { 100 try { 101 mDisplayName = new String(params, "US-ASCII"); 102 } catch (UnsupportedEncodingException e) { 103 Slog.e(TAG, "Failed to get OSD name: " + e.getMessage()); 104 } 105 requestVendorId(); 106 return true; 107 } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) { 108 int requestOpcode = params[1] & 0xFF; 109 if (requestOpcode == HdmiCec.MESSAGE_SET_OSD_NAME) { 110 requestVendorId(); 111 return true; 112 } 113 } 114 } else if (mState == STATE_WAITING_FOR_DEVICE_VENDOR_ID) { 115 if (opcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) { 116 if (params.length == 3) { 117 mVendorId = ((params[0] & 0xFF) << 16) + ((params[1] & 0xFF) << 8) 118 + (params[2] & 0xFF); 119 } else { 120 Slog.e(TAG, "Failed to get device vendor ID: "); 121 } 122 addDeviceInfo(); 123 finish(); 124 return true; 125 } else if (opcode == HdmiCec.MESSAGE_FEATURE_ABORT) { 126 int requestOpcode = params[1] & 0xFF; 127 if (requestOpcode == HdmiCec.MESSAGE_DEVICE_VENDOR_ID) { 128 addDeviceInfo(); 129 finish(); 130 return true; 131 } 132 } 133 } 134 return false; 135 } 136 137 private boolean mayProcessCommandIfCached(int destAddress, int opcode) { 138 HdmiCecMessage message = mService.getCecMessageCache().getMessage(destAddress, opcode); 139 if (message != null) { 140 return processCommand(message); 141 } 142 return false; 143 } 144 145 private void requestVendorId() { 146 // At first, transit to waiting status for <Device Vendor Id>. 147 mState = STATE_WAITING_FOR_DEVICE_VENDOR_ID; 148 // If the message is already in cache, process it. 149 if (mayProcessCommandIfCached(mDeviceLogicalAddress, HdmiCec.MESSAGE_DEVICE_VENDOR_ID)) { 150 return; 151 } 152 sendCommand(HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(mSourceAddress, 153 mDeviceLogicalAddress)); 154 addTimer(mState, TIMEOUT_MS); 155 } 156 157 private void addDeviceInfo() { 158 if (mDisplayName == null) { 159 mDisplayName = HdmiCec.getDefaultDeviceName(mDeviceLogicalAddress); 160 } 161 mService.addCecDevice(new HdmiCecDeviceInfo( 162 mDeviceLogicalAddress, mDevicePhysicalAddress, 163 HdmiCec.getTypeFromAddress(mDeviceLogicalAddress), 164 mVendorId, mDisplayName)); 165 } 166 167 @Override 168 public void handleTimerEvent(int state) { 169 if (mState == STATE_NONE || mState != state) { 170 return; 171 } 172 if (state == STATE_WAITING_FOR_SET_OSD_NAME) { 173 // Osd name request timed out. Try vendor id 174 requestVendorId(); 175 } else if (state == STATE_WAITING_FOR_DEVICE_VENDOR_ID) { 176 // vendor id timed out. Go ahead creating the device info what we've got so far. 177 addDeviceInfo(); 178 finish(); 179 } 180 } 181} 182