HdmiControlService.java revision e9cf1583c74fd03977c1ecb14520663710f14439
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; 286d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 29d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 30ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 3142c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 3267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 3478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 35e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 3678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 398b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 4078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 414893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 43a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 4678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 4802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 49a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 5878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 5978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 60d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 61d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 62d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 63d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 64d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 65d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 66d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 67ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 68ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 69ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 70ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 74d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 7502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 7602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 7702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 7802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 7902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 8102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 8202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 9278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 9378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 9478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 9778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 9978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1004893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 10178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 10278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1044893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 10578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 10678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 10778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1104893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1144893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 118ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 119ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 120ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 121ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 122ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 123ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 124ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 125ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 1370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 1380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 1410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 1420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 1430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1472f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 148e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 1498b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 1503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 1513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 152a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 1530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 1540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 156e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 1570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 1580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 1590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mPortInfo = initPortInfo(); 1618692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 16263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 16363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 16463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 1650792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 166e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 167a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private void initializeLocalDevices(final List<Integer> deviceTypes) { 169a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 1703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 1713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 1723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 17313c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim mCecController.clearLogicalAddress(); 1743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 1753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 1763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 1773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 1783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 1793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 1813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { 1823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 1843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 1853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 1863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 1873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 1883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 1893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 1913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1924893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 1930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 1943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 1953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 1983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 201a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 203a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 2053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 2063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 20713c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim device.handleAddressAllocated(address); 2083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 2120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 213a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> initPortInfo() { 215a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 2170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 2190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 2210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 2220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 2240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.emptyList(); 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mMhlController != null) { 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // TODO: Implement plumbing logic to get MHL port information. 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mhlPortInfo = mMhlController.getPortInfos(); 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Use the id (port number) to find the matched info between CEC and MHL to combine them 2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. 2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 2360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < cecPortInfo.length; ++i) { 2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo cec = cecPortInfo[i]; 2380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int id = cec.getId(); 2390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim boolean mhlInfoFound = false; 2400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo mhl : mhlPortInfo) { 2410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (id == mhl.getId()) { 2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), 2430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); 2440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mhlInfoFound = true; 2450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim break; 2460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (!mhlInfoFound) { 2490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(cec); 2500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(result); 2540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 2570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 2580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 2590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 2600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 2610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 2620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 2630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mPortInfo is an unmodifiable list and the only reference to its inner list. 2640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // No lock is necessary. 2650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 2660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (portId == info.getId()) { 2670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return info; 2680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return null; 2710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 273e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 274401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 275401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 276401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 277401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 278401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 279401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 280401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 28160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PHYSICAL_ADDRESS; 282401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 283401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 284401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 285401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 286401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 287401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 288401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 289401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 290401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 291401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 292401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 293401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK; 294401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 295401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portAddress == info.getAddress()) { 296401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return info.getId(); 297401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 298401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 29960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PORT_ID; 300401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 301401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 302401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 303e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 304e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 305e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 306e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 307e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 308e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 309e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 310e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 311e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 312e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 313e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 314e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 315e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 316e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 317e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 31867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 319e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 320c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 321c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 3223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 3233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 3253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 3263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 3293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 3303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 3323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 3333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 335a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 336a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 3370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 33879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 33979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 34079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 34179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 34279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 343a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 344a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 3453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 346092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 35360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 35460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 35560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 35660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiPortInfo portInfo : mPortInfo) { 35760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (hasSameTopPort(portInfo.getAddress(), physicalAddress) 35860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang && portInfo.isArcSupported()) { 35960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return true; 36060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 36360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 36579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 36667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 36767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 36867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 36963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 37063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 37163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 37363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 37463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 37563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 37663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 37967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 380c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 381c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 382c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 383d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 384c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 385a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 386d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 387a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 388d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 389d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 390d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 391a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 392d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 393a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 394d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 395c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 396c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 397a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 398a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 399a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 400092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 401092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 402092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 40379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 40479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 40560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 40660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 407a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 408092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 409a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 410092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 41179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 41279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang && message.getDestination() != HdmiCec.ADDR_BROADCAST) { 413092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 414092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 415092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 41660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 41760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 418092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 419a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 420a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 42167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 42267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 42367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 4248b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 42567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 42667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 427a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 42867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 42960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 43079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 43179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 43260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 43467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 43567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 43602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 43702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 43802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 43902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 44002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 4410f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 44202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 4430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 44402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 445a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4460f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { 447a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4480f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mCecController.pollDevices(callback, checkPollStrategy(pickStrategy), retryCount); 4490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 4510f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 4523ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK; 4530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 4540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 4550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4563ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK; 4570f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 4580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 4590f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4600f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 46102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 46360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 46460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 46560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 46660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 46760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 46879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 46979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 47079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 47179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 47279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 47379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // TODO: Hook up with AudioManager. 4743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 476ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 477ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 478ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 479ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 480ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 481ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 4823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 48342c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 48442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 4853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 4863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 4873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 48978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 49078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 49178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 49278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 49378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 49478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 49578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 49678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 49778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 49878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 49978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 50078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 50178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 50278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 50378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 5076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 5086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 5096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 5116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 5126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 515ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 5166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 5176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 5186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 5196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5206d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 523ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 524ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private IHdmiSystemAudioModeChangeListener mListener; 525ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 526ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 527ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 528ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 529ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 530ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 531ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 532ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 533ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 534ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 535ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 536ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 537ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 538ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 53978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 54078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 54178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 54278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 54378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 54478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 54578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 54678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 5480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 5490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 5500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 55178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 5520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 55378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 55578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 556a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 557a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 558a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 559a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 560a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 56179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 562a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 563a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 564a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 565a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 566a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 567a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 568a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 569a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 570a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 571a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 572a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 573a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 574a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 575a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 576a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 577a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 578a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 579a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 580a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 581a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 582a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 583a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 584a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim tv.portSelect(portId, callback); 585a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 586a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 587a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 588a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 589a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 590a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void sendKeyEvent(final int keyCode, final boolean isPressed) { 591a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 592a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 593a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 594a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 595a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // TODO: sendKeyEvent is for TV device only for now. Allow other 596a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // local devices of different types to use this as well. 597a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 598a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 599a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 600a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 601a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 602a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim tv.sendKeyEvent(keyCode, isPressed); 603a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 604a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 605a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 606a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 607a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 6087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 60978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 6147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 61678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 61778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 61878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6197fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 62078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 6257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 62778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 62878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 62978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 63178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 6367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 63878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 63978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 64078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 64278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 6477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 64978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 6506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 6526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 6536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 6546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 6556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 656ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 6576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 6586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 6606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 6636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 6646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 6656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 6666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 667ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 668ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 669ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 670ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 671ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 672ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 673ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 674ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 675e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 676ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 677ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 678ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 679ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 680ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 681ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 682ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 683ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 684ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 685ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return tv.getSystemAudioMode(); 686ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 687ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 688ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 689ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 690ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 691ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 692ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 693ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 694ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 695ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 696ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 697ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 698ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 699ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 700ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 701ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 702ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 703ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 704ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 705ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 706ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 707ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 708ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 709ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 710ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 711ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 712ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 713ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 714ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 715ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 716ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 717ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 71878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 71978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 720a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 72179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 72279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 72379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 7247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 7257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 7267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 7277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 7287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 72979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 73078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 73178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 732a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 73379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 73479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 73579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 7367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 7377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 7387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 7397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 7407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 74179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 74278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 74378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 74478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 74578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 74678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 74778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 74878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 74978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 75078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 75178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 75378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 75478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 75578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 75878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 75978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 76078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 76178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 76278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 76378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 76478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 76578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 76678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 76778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 76878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 76978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 7716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 7724893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 7734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 7744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 7754893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 7764893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 7774893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 7784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7796d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 7804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 7814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 7824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 7854893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 7864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 7874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 7884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 7894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 7904893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 7914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 7926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 797ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 798ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 799ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 800ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 801ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 802ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 803ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 804ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 805ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 806ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 807ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 808ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 809ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 810ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 811ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 812ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 813ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 814ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 815ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 816ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 817ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 818ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 819ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 820ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 821ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 822ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 823ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 824ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 825ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 8267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 8277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 8287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 8297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 8307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 8317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 83363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 834ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 835ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 836ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 837ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 838ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 839ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 840ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 841ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 842ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 8434893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 8444893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 84560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 84660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 8474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 84860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 84960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 8524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 85360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 85460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 85560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 85660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 85760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 85860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 859e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 860e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 86160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 86260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) 86360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); 86460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 86560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 86679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 86779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); 86879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 86979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 87079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 87179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 87260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 8730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 874