1cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang/* 2cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 3cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 4cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 5cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * you may not use this file except in compliance with the License. 6cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * You may obtain a copy of the License at 7cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 8cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 9cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 10cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Unless required by applicable law or agreed to in writing, software 11cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 12cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * See the License for the specific language governing permissions and 14cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * limitations under the License. 15cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 16cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 17cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangpackage com.android.server.hdmi; 18cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 20cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport android.util.Slog; 21cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 22cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport com.android.internal.util.Preconditions; 23cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport com.android.server.hdmi.HdmiControlService.DevicePollingCallback; 24cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 25cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport java.io.UnsupportedEncodingException; 26cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport java.util.ArrayList; 27cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jangimport java.util.List; 28cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 29cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang/** 30cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Feature action that handles device discovery sequences. 31cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Device discovery is launched when TV device is woken from "Standby" state 32cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * or enabled "Control for Hdmi" from disabled state. 33cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 34cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <p>Device discovery goes through the following steps. 35cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <ol> 36cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <li>Poll all non-local devices by sending <Polling Message> 37cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <li>Gather "Physical address" and "device type" of all acknowledged devices 38cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <li>Gather "OSD (display) name" of all acknowledge devices 39cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * <li>Gather "Vendor id" of all acknowledge devices 40cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * </ol> 4146350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo * We attempt to get OSD name/vendor ID up to 5 times in case the communication fails. 42cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 43b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jangfinal class DeviceDiscoveryAction extends HdmiCecFeatureAction { 44cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final String TAG = "DeviceDiscoveryAction"; 45cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 46cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // State in which the action is waiting for device polling. 47cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final int STATE_WAITING_FOR_DEVICE_POLLING = 1; 48cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // State in which the action is waiting for gathering physical address of non-local devices. 49cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final int STATE_WAITING_FOR_PHYSICAL_ADDRESS = 2; 50cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // State in which the action is waiting for gathering osd name of non-local devices. 51cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final int STATE_WAITING_FOR_OSD_NAME = 3; 52cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // State in which the action is waiting for gathering vendor id of non-local devices. 53cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final int STATE_WAITING_FOR_VENDOR_ID = 4; 54cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 55cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang /** 56cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Interface used to report result of device discovery. 57cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 58cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang interface DeviceDiscoveryCallback { 59cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang /** 60cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * Called when device discovery is done. 61cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 62cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * @param deviceInfos a list of all non-local devices. It can be empty list. 63cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 6461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos); 65cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 66cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 67cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // An internal container used to keep track of device information during 68cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // this action. 69cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private static final class DeviceInfo { 70cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private final int mLogicalAddress; 71cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 72c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPhysicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; 732b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private int mPortId = Constants.INVALID_PORT_ID; 74c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mVendorId = Constants.UNKNOWN_VENDOR_ID; 75cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private String mDisplayName = ""; 7661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private int mDeviceType = HdmiDeviceInfo.DEVICE_INACTIVE; 77cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 78cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private DeviceInfo(int logicalAddress) { 79cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mLogicalAddress = logicalAddress; 80cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 81cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 8261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private HdmiDeviceInfo toHdmiDeviceInfo() { 8361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(mLogicalAddress, mPhysicalAddress, mPortId, mDeviceType, 842b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim mVendorId, mDisplayName); 85cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 86cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 87cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 88cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private final ArrayList<DeviceInfo> mDevices = new ArrayList<>(); 89cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private final DeviceDiscoveryCallback mCallback; 90cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private int mProcessedDeviceCount = 0; 9146350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo private int mTimeoutRetry = 0; 92cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 93cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang /** 94e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang * Constructor. 95cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang * 9679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param source an instance of {@link HdmiCecLocalDevice}. 97cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang */ 9879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang DeviceDiscoveryAction(HdmiCecLocalDevice source, DeviceDiscoveryCallback callback) { 9979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang super(source); 100cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCallback = Preconditions.checkNotNull(callback); 101cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 102cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 103cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang @Override 104cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang boolean start() { 105cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mDevices.clear(); 106cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mState = STATE_WAITING_FOR_DEVICE_POLLING; 107cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 10879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang pollDevices(new DevicePollingCallback() { 109cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang @Override 110cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang public void onPollingFinished(List<Integer> ackedAddress) { 111cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (ackedAddress.isEmpty()) { 1128b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "No device is detected."); 113ad2eefe97935db5282da18459b8da22b48207d83Jungshik Jang wrapUpAndFinish(); 114cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 115cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 116cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 1178b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "Device detected: " + ackedAddress); 118cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang allocateDevices(ackedAddress); 119cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang startPhysicalAddressStage(); 120cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 121c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim }, Constants.POLL_ITERATION_REVERSE_ORDER 1225fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim | Constants.POLL_STRATEGY_REMOTES_DEVICES, HdmiConfig.DEVICE_POLLING_RETRY); 123cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return true; 124cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 125cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 126cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void allocateDevices(List<Integer> addresses) { 127cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang for (Integer i : addresses) { 128cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang DeviceInfo info = new DeviceInfo(i); 129cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mDevices.add(info); 130cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 131cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 132cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 133cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void startPhysicalAddressStage() { 1348b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "Start [Physical Address Stage]:" + mDevices.size()); 135cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mProcessedDeviceCount = 0; 136cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mState = STATE_WAITING_FOR_PHYSICAL_ADDRESS; 137cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 138cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 139cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 140cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 141cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private boolean verifyValidLogicalAddress(int address) { 142c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return address >= Constants.ADDR_TV && address < Constants.ADDR_UNREGISTERED; 143cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 144cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 145cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void queryPhysicalAddress(int address) { 146cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (!verifyValidLogicalAddress(address)) { 147cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 148cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 149cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 150cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 151cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mActionTimer.clearTimerMessage(); 152e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 153e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang // Check cache first and send request if not exist. 154c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mayProcessMessageIfCached(address, Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS)) { 155e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return; 156e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 15779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang sendCommand(HdmiCecMessageBuilder.buildGivePhysicalAddress(getSourceAddress(), address)); 1585fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim addTimer(mState, HdmiConfig.TIMEOUT_MS); 159cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 160cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 161cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void startOsdNameStage() { 1628b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "Start [Osd Name Stage]:" + mDevices.size()); 163cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mProcessedDeviceCount = 0; 164cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mState = STATE_WAITING_FOR_OSD_NAME; 165cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 166cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 167cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 168cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 169cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void queryOsdName(int address) { 170cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (!verifyValidLogicalAddress(address)) { 171cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 172cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 173cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 174cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 175cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mActionTimer.clearTimerMessage(); 176e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 177c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mayProcessMessageIfCached(address, Constants.MESSAGE_SET_OSD_NAME)) { 178e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return; 179e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 18079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang sendCommand(HdmiCecMessageBuilder.buildGiveOsdNameCommand(getSourceAddress(), address)); 1815fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim addTimer(mState, HdmiConfig.TIMEOUT_MS); 182cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 183cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 184cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void startVendorIdStage() { 1858b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "Start [Vendor Id Stage]:" + mDevices.size()); 1868b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 187cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mProcessedDeviceCount = 0; 188cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mState = STATE_WAITING_FOR_VENDOR_ID; 189cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 190cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 191cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 192cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 193cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void queryVendorId(int address) { 194cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (!verifyValidLogicalAddress(address)) { 195cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 196cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 197cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 198cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 199cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mActionTimer.clearTimerMessage(); 200e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 201c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mayProcessMessageIfCached(address, Constants.MESSAGE_DEVICE_VENDOR_ID)) { 202e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return; 203e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 20479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang sendCommand( 20579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecMessageBuilder.buildGiveDeviceVendorIdCommand(getSourceAddress(), address)); 2065fba96df30b6b50b3cb9fe1d783320b1cc3bd6eaJinsuk Kim addTimer(mState, HdmiConfig.TIMEOUT_MS); 207cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 208cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 209e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang private boolean mayProcessMessageIfCached(int address, int opcode) { 21079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecMessage message = getCecMessageCache().getMessage(address, opcode); 211e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang if (message != null) { 212e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang processCommand(message); 213e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return true; 214e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 215e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang return false; 216e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 217e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 218cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang @Override 219cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang boolean processCommand(HdmiCecMessage cmd) { 220cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang switch (mState) { 221cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_PHYSICAL_ADDRESS: 222c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (cmd.getOpcode() == Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS) { 223cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang handleReportPhysicalAddress(cmd); 224cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return true; 225cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 226cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return false; 227cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_OSD_NAME: 228c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (cmd.getOpcode() == Constants.MESSAGE_SET_OSD_NAME) { 229cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang handleSetOsdName(cmd); 230cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return true; 231cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 232cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return false; 233cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_VENDOR_ID: 234c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (cmd.getOpcode() == Constants.MESSAGE_DEVICE_VENDOR_ID) { 235cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang handleVendorId(cmd); 236cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return true; 237cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 238cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return false; 239cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_DEVICE_POLLING: 240cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // Fall through. 241cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang default: 242cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return false; 243cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 244cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 245cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 246cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void handleReportPhysicalAddress(HdmiCecMessage cmd) { 247cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Preconditions.checkState(mProcessedDeviceCount < mDevices.size()); 248cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 249cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang DeviceInfo current = mDevices.get(mProcessedDeviceCount); 250cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (current.mLogicalAddress != cmd.getSource()) { 251cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:" + 252cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang cmd.getSource()); 253cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 254cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 255cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 256cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang byte params[] = cmd.getParams(); 25775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo current.mPhysicalAddress = HdmiUtils.twoBytesToInt(params); 2582b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim current.mPortId = getPortId(current.mPhysicalAddress); 25975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo current.mDeviceType = params[2] & 0xFF; 260cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 261bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim tv().updateCecSwitchInfo(current.mLogicalAddress, current.mDeviceType, 262bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim current.mPhysicalAddress); 263bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim 26475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo increaseProcessedDeviceCount(); 26575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo checkAndProceedStage(); 266cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 267cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 2682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private int getPortId(int physicalAddress) { 2692b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return tv().getPortId(physicalAddress); 2702b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 2712b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 272cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void handleSetOsdName(HdmiCecMessage cmd) { 273cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Preconditions.checkState(mProcessedDeviceCount < mDevices.size()); 274cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 275cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang DeviceInfo current = mDevices.get(mProcessedDeviceCount); 276cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (current.mLogicalAddress != cmd.getSource()) { 277cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:" + 278cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang cmd.getSource()); 279cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 280cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 281cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 282cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang String displayName = null; 283cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang try { 284cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang displayName = new String(cmd.getParams(), "US-ASCII"); 285cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } catch (UnsupportedEncodingException e) { 286cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Slog.w(TAG, "Failed to decode display name: " + cmd.toString()); 287cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // If failed to get display name, use the default name of device. 288c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim displayName = HdmiUtils.getDefaultDeviceName(current.mLogicalAddress); 289cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 290cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang current.mDisplayName = displayName; 291cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang increaseProcessedDeviceCount(); 292cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 293cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 294cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 295cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void handleVendorId(HdmiCecMessage cmd) { 296cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Preconditions.checkState(mProcessedDeviceCount < mDevices.size()); 297cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 298cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang DeviceInfo current = mDevices.get(mProcessedDeviceCount); 299cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (current.mLogicalAddress != cmd.getSource()) { 300cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang Slog.w(TAG, "Unmatched address[expected:" + current.mLogicalAddress + ", actual:" + 301cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang cmd.getSource()); 302cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 303cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 304cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 305cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang byte[] params = cmd.getParams(); 30675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo int vendorId = HdmiUtils.threeBytesToInt(params); 30775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo current.mVendorId = vendorId; 308cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang increaseProcessedDeviceCount(); 309cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 310cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 311cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 312cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void increaseProcessedDeviceCount() { 313cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mProcessedDeviceCount++; 31446350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo mTimeoutRetry = 0; 315cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 316cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 317cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void removeDevice(int index) { 318cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mDevices.remove(index); 319cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 320cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 321cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void wrapUpAndFinish() { 3228b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "---------Wrap up Device Discovery:[" + mDevices.size() + "]---------"); 32361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang ArrayList<HdmiDeviceInfo> result = new ArrayList<>(); 324cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang for (DeviceInfo info : mDevices) { 32561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo cecDeviceInfo = info.toHdmiDeviceInfo(); 3268b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, " DeviceInfo: " + cecDeviceInfo); 327cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang result.add(cecDeviceInfo); 328cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 3298b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "--------------------------------------------"); 330cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mCallback.onDeviceDiscoveryDone(result); 331cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang finish(); 3327fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Process any commands buffered while device discovery action was in progress. 3337fa3a66470d2133796defd14a0600578758882acJinsuk Kim tv().processAllDelayedMessages(); 334cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 335cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 336cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang private void checkAndProceedStage() { 337cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (mDevices.isEmpty()) { 338cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang wrapUpAndFinish(); 339cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 340cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 341cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 342cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang // If finished current stage, move on to next stage. 343cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (mProcessedDeviceCount == mDevices.size()) { 344cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang mProcessedDeviceCount = 0; 345cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang switch (mState) { 346cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_PHYSICAL_ADDRESS: 347cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang startOsdNameStage(); 348cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 349cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_OSD_NAME: 350cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang startVendorIdStage(); 351cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 352cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang case STATE_WAITING_FOR_VENDOR_ID: 353cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang wrapUpAndFinish(); 354cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 355cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang default: 356cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 357cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 358cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } else { 35946350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo sendQueryCommand(); 36046350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo } 36146350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo } 36246350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo 36346350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo private void sendQueryCommand() { 36446350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo int address = mDevices.get(mProcessedDeviceCount).mLogicalAddress; 36546350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo switch (mState) { 36646350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo case STATE_WAITING_FOR_PHYSICAL_ADDRESS: 36746350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo queryPhysicalAddress(address); 36846350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo return; 36946350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo case STATE_WAITING_FOR_OSD_NAME: 37046350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo queryOsdName(address); 37146350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo return; 37246350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo case STATE_WAITING_FOR_VENDOR_ID: 37346350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo queryVendorId(address); 37446350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo default: 37546350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo return; 376cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 377cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 378cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 379cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang @Override 380cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang void handleTimerEvent(int state) { 381cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang if (mState == STATE_NONE || mState != state) { 382cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang return; 383cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 384cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang 38546350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo if (++mTimeoutRetry < HdmiConfig.TIMEOUT_RETRY) { 38646350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo sendQueryCommand(); 38746350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo return; 38846350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo } 38946350382ee1974fd635d43c7273dc44854edf7c7Yuncheol Heo mTimeoutRetry = 0; 3908b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang Slog.v(TAG, "Timeout[State=" + mState + ", Processed=" + mProcessedDeviceCount); 391cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang removeDevice(mProcessedDeviceCount); 392cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang checkAndProceedStage(); 393cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang } 394cc5ef8c918e96516a5c51cc40735a1b8a24d8497Jungshik Jang} 395