HdmiCecLocalDeviceTv.java revision 0a3316bcfdac9f5f40d1349d97d10329c70f7e30
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.IHdmiControlCallback; 20import android.hardware.hdmi.HdmiCec; 21import android.hardware.hdmi.HdmiCecDeviceInfo; 22import android.hardware.hdmi.HdmiCecMessage; 23import android.os.RemoteException; 24import android.util.Slog; 25 26import java.util.Collections; 27import java.util.List; 28import java.util.Locale; 29 30/** 31 * Represent a logical device of type TV residing in Android system. 32 */ 33final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { 34 private static final String TAG = "HdmiCecLocalDeviceTv"; 35 36 HdmiCecLocalDeviceTv(HdmiControlService service) { 37 super(service, HdmiCec.DEVICE_TV); 38 } 39 40 @Override 41 protected void onAddressAllocated(int logicalAddress) { 42 // TODO: vendor-specific initialization here. 43 44 mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 45 mAddress, mService.getPhysicalAddress(), mDeviceType)); 46 mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 47 mAddress, mService.getVendorId())); 48 49 mService.launchDeviceDiscovery(mAddress); 50 // TODO: Start routing control action, device discovery action. 51 } 52 53 @Override 54 protected boolean onMessage(HdmiCecMessage message) { 55 switch (message.getOpcode()) { 56 case HdmiCec.MESSAGE_REPORT_PHYSICAL_ADDRESS: 57 return handleReportPhysicalAddress(message); 58 default: 59 return super.onMessage(message); 60 } 61 } 62 63 /** 64 * Performs the action 'device select', or 'one touch play' initiated by TV. 65 * 66 * @param targetAddress logical address of the device to select 67 * @param callback callback object to report the result with 68 */ 69 void deviceSelect(int targetAddress, IHdmiControlCallback callback) { 70 HdmiCecDeviceInfo targetDevice = mService.getDeviceInfo(targetAddress); 71 if (targetDevice == null) { 72 invokeCallback(callback, HdmiCec.RESULT_TARGET_NOT_AVAILABLE); 73 return; 74 } 75 mService.removeAction(DeviceSelectAction.class); 76 mService.addAndStartAction(new DeviceSelectAction(mService, mAddress, 77 mService.getPhysicalAddress(), targetDevice, callback)); 78 } 79 80 private static void invokeCallback(IHdmiControlCallback callback, int result) { 81 try { 82 callback.onComplete(result); 83 } catch (RemoteException e) { 84 Slog.e(TAG, "Invoking callback failed:" + e); 85 } 86 } 87 88 @Override 89 protected boolean handleGetMenuLanguage(HdmiCecMessage message) { 90 HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( 91 mAddress, Locale.getDefault().getISO3Language()); 92 // TODO: figure out how to handle failed to get language code. 93 if (command != null) { 94 mService.sendCecCommand(command); 95 } else { 96 Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString()); 97 } 98 return true; 99 } 100 101 private boolean handleReportPhysicalAddress(HdmiCecMessage message) { 102 // Ignore if [Device Discovery Action] is going on. 103 if (mService.hasAction(DeviceDiscoveryAction.class)) { 104 Slog.i(TAG, "Ignore unrecognizable <Report Physical Address> " 105 + "because Device Discovery Action is on-going:" + message); 106 return true; 107 } 108 109 int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); 110 mService.addAndStartAction(new NewDeviceAction(mService, 111 mAddress, message.getSource(), physicalAddress)); 112 113 return true; 114 } 115 116 @Override 117 protected boolean handleVendorSpecificCommand(HdmiCecMessage message) { 118 List<VendorSpecificAction> actions = Collections.emptyList(); 119 // TODO: Call mService.getActions(VendorSpecificAction.class) to get all the actions. 120 121 // We assume that there can be multiple vendor-specific command actions running 122 // at the same time. Pass the message to each action to see if one of them needs it. 123 for (VendorSpecificAction action : actions) { 124 if (action.processCommand(message)) { 125 return true; 126 } 127 } 128 // Handle the message here if it is not already consumed by one of the running actions. 129 // Respond with a appropriate vendor-specific command or <Feature Abort>, or create another 130 // vendor-specific action: 131 // 132 // mService.addAndStartAction(new VendorSpecificAction(mService, mAddress)); 133 // 134 // For now, simply reply with <Feature Abort> and mark it consumed by returning true. 135 mService.sendCecCommand(HdmiCecMessageBuilder.buildFeatureAbortCommand( 136 message.getDestination(), message.getSource(), message.getOpcode(), 137 HdmiConstants.ABORT_REFUSED)); 138 return true; 139 } 140} 141