HdmiControlService.java revision 79c58a4b97f27ede6a1b680d2fece9c2a0edf7b7
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 21a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport android.hardware.hdmi.HdmiCec; 22c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 23c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecMessage; 2460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 26d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 27d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 28d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 2942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 3067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 3278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 33e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 3478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 378b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 3878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 4278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 4402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 45a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 5478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 5578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_SUCCESS = 0; 57ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_NAK = -1; 58ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo static final int SEND_RESULT_FAILURE = -2; 59ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo 600f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_MASK = 0x3; // first and second bit. 610f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_REMOTES_DEVICES = 0x1; 620f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_STRATEGY_SYSTEM_AUDIO = 0x2; 630f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 640f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_STRATEGY_MASK = 0x30000; // first and second bit. 650f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_IN_ORDER = 0x10000; 660f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang static final int POLL_ITERATION_REVERSE_ORDER = 0x20000; 670f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 68d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 70d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 74d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 75ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 76ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 77ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 78ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 79d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 82d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 8702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 8902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 9002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 9102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 9202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 9302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 9402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 10078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 10178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 10278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 10578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 10778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 10878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 10978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 11178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 11278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 11378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Handler running on service thread. It's used to run a task in service thread. 1150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 1250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 1260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 1290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 1300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 1310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1352f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 136e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 1378b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 1383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 1393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 140a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 1410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 1420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 144e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 1470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mPortInfo = initPortInfo(); 1498692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 15063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 15163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 15263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 1530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 154e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 1550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private void initializeLocalDevices(final List<Integer> deviceTypes) { 1563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 1573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 1583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 1593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 1603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 1613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 1623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 1633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 1643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 1653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 1663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { 1673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 1683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 1693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 1703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 1713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 1723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 1733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 1743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 1763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // Once finish address allocation for all devices, notify 1783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // it to each device. 1790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 1813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 1843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 1883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 1893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 1903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 1913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang device.onAddressAllocated(address); 1923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 1960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 1970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> initPortInfo() { 1980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 1990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 2010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 2020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 2030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 2040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 2060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.emptyList(); 2070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; 2100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mMhlController != null) { 2110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // TODO: Implement plumbing logic to get MHL port information. 2120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mhlPortInfo = mMhlController.getPortInfos(); 2130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Use the id (port number) to find the matched info between CEC and MHL to combine them 2160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. 2170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 2180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < cecPortInfo.length; ++i) { 2190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo cec = cecPortInfo[i]; 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int id = cec.getId(); 2210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim boolean mhlInfoFound = false; 2220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo mhl : mhlPortInfo) { 2230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (id == mhl.getId()) { 2240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); 2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mhlInfoFound = true; 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim break; 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (!mhlInfoFound) { 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(cec); 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(result); 2360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 2390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 2400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 2410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 2430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 2440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 2450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mPortInfo is an unmodifiable list and the only reference to its inner list. 2460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // No lock is necessary. 2470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 2480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (portId == info.getId()) { 2490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return info; 2500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return null; 2530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 255e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 256401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 257401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 258401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 259401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 260401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 261401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 262401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 26360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PHYSICAL_ADDRESS; 264401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 265401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 266401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 267401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 268401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 269401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 270401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 271401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 272401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 273401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 274401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 275401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK; 276401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 277401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portAddress == info.getAddress()) { 278401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return info.getId(); 279401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 280401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 28160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PORT_ID; 282401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 283401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 284401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 285e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 286e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 287e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 288e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 289e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 290e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 291e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 292e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 293e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 294e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 295e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 296e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 297e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 298e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 299e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 30067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 301e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 302c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 303c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 3043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 3053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 3073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 3083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 3113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 3123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 3143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 3153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 317a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 3180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 31979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 32079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 32179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 32279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 32379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 324a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 325a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 3263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 327092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 329092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 330092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 331092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 332092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 333092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 33460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 33560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 33660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 33760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiPortInfo portInfo : mPortInfo) { 33860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (hasSameTopPort(portInfo.getAddress(), physicalAddress) 33960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang && portInfo.isArcSupported()) { 34060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return true; 34160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 34260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 34360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 34460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 34560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 34679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 34767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 34867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 34967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 35063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 35163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 35263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 35363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 35463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 35563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 35663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 35763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 35863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 35963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 36067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 361c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 362c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 363c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 364d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 365c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 366d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 367d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 368d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 369d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 370d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 371d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 372c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 373c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 374a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 375092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 376092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 377092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 37879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 37979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 38060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 38160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 382092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 383092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 38479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 38579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang && message.getDestination() != HdmiCec.ADDR_BROADCAST) { 386092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 387092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 388092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 38960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 39060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 391092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 392a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 393a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 39467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 39567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 39667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 3978b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 39867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 39967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 40067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 40160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 40279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 40379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 40479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 40560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 40660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 40760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 40867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 40967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 41002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 41102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 41202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 41302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 41402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 4150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 41602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 4170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 41802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 4190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { 4200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mCecController.pollDevices(callback, checkPollStrategy(pickStrategy), retryCount); 4210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 4230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 4240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang int strategy = pickStrategy & POLL_STRATEGY_MASK; 4250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 4260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 4270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang int iterationStrategy = pickStrategy & POLL_ITERATION_STRATEGY_MASK; 4290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 4300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 4310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 43302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 43402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 43560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 43660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 43760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 43860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 44079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 44179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 44279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 44379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 44479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 44579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // TODO: Hook up with AudioManager. 4463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 44942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 45042c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 4513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 4523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 4533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 45578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 45678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 45778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 45878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 45978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 46078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 46178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 46278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 46378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 46478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 46578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 46678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 46778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 46878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 46978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 47078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 47178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 47278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 47378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 47478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 47578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 47678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 47778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 47878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 47978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 48078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 4810340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 4820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 4830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 4840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 48578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 4860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 48778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 48878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 48978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 490a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 491a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 492a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 493a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 494a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 49579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 496a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 497a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim Slog.w(TAG, "Local playback device not available"); 498a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 499a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 500a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 501a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 502a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 503a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 504a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 505a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 506a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 5077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 50878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 5137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 51578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 51678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 51778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 5187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 51978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 5247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 52678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 52778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 52878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 5297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 53078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 5357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 53778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 53878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 53978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 5407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 54178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 5437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 5447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 5457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 5467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 5477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 54878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 54978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 55179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 55279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 55379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 5547fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 5557fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 5567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 5577fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5587fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 55979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 56078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 56379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 56479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 5657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 5667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 5677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 5687fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 5697fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 57079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 57178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 57378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 57478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 57578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 57678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 57778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 57878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 57978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 58078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 58278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 58378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 58478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 58778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 58878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 58978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 59078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 59178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 59278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 59378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 59478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 59578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 59678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 59778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 59878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 5997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 6007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 6017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 6027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 6037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 6047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 6057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 60763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 60860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void announceHotplugEvent(int portNo, boolean connected) { 60960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event = new HdmiHotplugEvent(portNo, connected); 61060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 61160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 61260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang invokeHotplugEventListener(listener, event); 61360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 61760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void invokeHotplugEventListener(IHdmiHotplugEventListener listener, 61860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 61960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 62060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 62160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 62260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 62360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 624e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 625e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 62660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 62760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) 62860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); 62960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 63060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 63179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 63279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); 63379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 63479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 63579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 63679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 63760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 6380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 639