HdmiControlService.java revision 8333571bd5e0a08773a1679964f8d96227af3356
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; 31a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 3242c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 3367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 3578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 36e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 3778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 408b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 4178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 424893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 44a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 4778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 4902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 50a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 5978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 6078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 61d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 62d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 63d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 64d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 65d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 66d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 67d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 68ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 69ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 70ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 71ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 74d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 75d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 7602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 7702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 7802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 7902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 8002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 8202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 8702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 9378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 9478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 9578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 9878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 10078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1014893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 10278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 10378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 10478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1054893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 10678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 10778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 10878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1114893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1154893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 119ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 120ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 121ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 122ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 123ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 124ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 125ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 126ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1274893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 1380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 1390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 1420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 1430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1482f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 149e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 1508b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 1513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 1523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 153a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 1540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 1550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 157e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 1580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 1590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 1600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mPortInfo = initPortInfo(); 1628692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 16363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 16463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 16563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 1660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 167e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 168a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private void initializeLocalDevices(final List<Integer> deviceTypes) { 170a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 1713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 1723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 1733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 17413c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim mCecController.clearLogicalAddress(); 1753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 1763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 1773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 1783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 1793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 1813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 1823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 1843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 1853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 1863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 1873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 1883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 1893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 1903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 1923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 1934893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 1940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 1953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 1963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 1993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 202a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 204a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 2063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 2073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 20813c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim device.handleAddressAllocated(address); 2093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 2130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 214a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> initPortInfo() { 216a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 2180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 2210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 2220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 2230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.emptyList(); 2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mMhlController != null) { 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // TODO: Implement plumbing logic to get MHL port information. 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mhlPortInfo = mMhlController.getPortInfos(); 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Use the id (port number) to find the matched info between CEC and MHL to combine them 2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. 2360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < cecPortInfo.length; ++i) { 2380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo cec = cecPortInfo[i]; 2390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int id = cec.getId(); 2400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim boolean mhlInfoFound = false; 2410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo mhl : mhlPortInfo) { 2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (id == mhl.getId()) { 2430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), 2440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); 2450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mhlInfoFound = true; 2460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim break; 2470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (!mhlInfoFound) { 2500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(cec); 2510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(result); 2550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 2580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 2590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 2600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 2610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 2620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 2630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 2640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mPortInfo is an unmodifiable list and the only reference to its inner list. 2650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // No lock is necessary. 2660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 2670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (portId == info.getId()) { 2680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return info; 2690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return null; 2720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 274e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 275401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 276401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 277401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 278401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 279401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 280401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 281401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 28260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PHYSICAL_ADDRESS; 283401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 284401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 285401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 286401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 287401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 288401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 289401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 290401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 291401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 292401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 293401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 294401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK; 295401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 296401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portAddress == info.getAddress()) { 297401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return info.getId(); 298401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 299401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 30060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PORT_ID; 301401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 302401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 303401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 304e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 305e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 306e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 307e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 308e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 309e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 310e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 311e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 312e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 313e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 314e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 315e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 316e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 317e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 318e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 31967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 320e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 321c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 322c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 3233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 3243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 3263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 3273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 3303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 3313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 3333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 3343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 336a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 337a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 3380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 33979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 34079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 34179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 34279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 34379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 344a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 345a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 3463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 353092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 35460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 35560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 35660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 35760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiPortInfo portInfo : mPortInfo) { 35860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (hasSameTopPort(portInfo.getAddress(), physicalAddress) 35960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang && portInfo.isArcSupported()) { 36060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return true; 36160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 36460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 36560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 36679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 36767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 36867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 36967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 37063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 37163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 37263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 37463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 37563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 37663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 37763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 37963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 38067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 381c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 382c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 383c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 384d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 385c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 386a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 387d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 388a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 389d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 390d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 391d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 392a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 393d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 394a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 395d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 396c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 397c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 398a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 399a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 400a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 401092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 402092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 403092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 40479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 40579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 40660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 40760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 408a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 409092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 410a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 411092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 41279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 41379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang && message.getDestination() != HdmiCec.ADDR_BROADCAST) { 414092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 415092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 416092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 41760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 41860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 419092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 420a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 421a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 42267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 42367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 42467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 4258b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 42667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 42767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 428a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 42967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 43060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 43179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 43279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 43360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 43567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 43667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 43702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 43802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 43902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 44002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 44102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 4420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 44302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 4440f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 44502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 446a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4470f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang void pollDevices(DevicePollingCallback callback, int pickStrategy, int retryCount) { 448a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4490f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang mCecController.pollDevices(callback, checkPollStrategy(pickStrategy), retryCount); 4500f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4510f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 4520f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 4533ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK; 4540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 4550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 4560f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4573ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK; 4580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 4590f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 4600f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 4610f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 46202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 46302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 46460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 46560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 46660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 46760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 46860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 46979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 47079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 47179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 47279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 47379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 47479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // TODO: Hook up with AudioManager. 4753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 477ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 478ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 479ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 480ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 481ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 482ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 4833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 48442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 48542c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 4863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 4873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 4883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 49078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 49178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 49278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 49378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 49478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 49578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 49678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 49778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 49878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 49978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 50078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 50178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 50278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 50378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 50478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 50778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 5086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 5096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 5106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 5126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 5136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 516ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 5176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 5186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 5196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 5206d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 524ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 525ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private IHdmiSystemAudioModeChangeListener mListener; 526ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 527ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 528ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 529ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 530ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 531ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 532ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 533ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 534ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 535ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 536ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 537ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 538ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 539ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 54078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 54178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 54278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 54378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 54478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 54578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 54678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 54778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 5480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 5490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 5500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 5510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 55278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 5530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 55478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 55578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 55678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 557a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 558a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 559a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 560a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 561a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 56279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 563a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 564a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 565a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 566a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 567a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 568a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 569a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 570a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 571a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 572a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 573a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 574a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 575a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 576a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 577a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 578a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 579a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 580a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 581a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 582a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 583a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 584a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 5858333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 586a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 587a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 588a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 589a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 590a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 591a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void sendKeyEvent(final int keyCode, final boolean isPressed) { 592a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 593a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 594a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 595a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 596a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // TODO: sendKeyEvent is for TV device only for now. Allow other 597a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // local devices of different types to use this as well. 598a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 599a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 600a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 601a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 602a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 603a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim tv.sendKeyEvent(keyCode, isPressed); 604a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 605a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 606a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 607a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 608a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 6097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 61078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 6157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 61778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 61878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 61978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 62178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 6267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 62878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 62978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 63078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 63278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 6377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 63978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 64178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 64378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 6487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 65078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 6516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 6536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 6546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 6556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 6566d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 657ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 6586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 6596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 6616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 6646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 6656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 6666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 6676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 668ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 669ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 670ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 671ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 672ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 673ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 674ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 675ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 676e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 677ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 678ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 679ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 680ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 681ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 682ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 683ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 684ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 685ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 686ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return tv.getSystemAudioMode(); 687ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 688ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 689ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 690ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 691ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 692ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 693ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 694ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 695ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 696ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 697ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 698ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 699ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 700ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 701ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 702ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 703ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 704ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 705ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 706ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 707ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 708ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 709ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 710ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 711ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 712ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 713ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 714ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 715ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 716ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 717ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 718ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 71978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 72078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 721a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 72279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 72379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 72479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 7257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 7267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 7277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 7287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 7297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 73079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 73178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 73278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 733a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 73479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 73579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 73679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 7377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 7387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 7397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 7407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 7417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 74279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 74378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 74478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 74578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 74678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 74778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 74878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 74978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 75078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 75178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 75278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 75478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 75578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 75678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 75978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 76078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 76178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 76278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 76378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 76478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 76578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 76678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 76778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 76878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 76978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 77078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 7726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 7734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 7744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 7754893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 7764893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 7774893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 7784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 7794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 7814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 7824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 7834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 7854893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 7864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 7874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 7884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 7894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 7904893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 7914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 7924893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 7936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 798ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 799ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 800ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 801ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 802ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 803ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 804ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 805ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 806ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 807ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 808ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 809ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 810ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 811ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 812ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 813ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 814ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 815ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 816ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 817ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 818ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 819ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 820ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 821ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 822ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 823ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 824ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 825ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 826ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 8277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 8287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 8297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 8307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 8317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 8327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 83463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 835ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 836ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 837ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 838ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 839ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 840ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 841ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 842ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 843ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 8444893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 8454893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 84660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 84760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 8484893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 84960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 8534893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 85460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 85560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 85660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 85760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 85860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 85960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 860e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 861e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 86260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 86360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) 86460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); 86560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 86660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 86779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 86879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); 86979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 87079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 87179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 87279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 87360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 874a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 875a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 876a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 877a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 8780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 879