HdmiControlService.java revision 347a60449981fc934e5a84122df87c1447665548
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; 2038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 2238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 2338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 24c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 25c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 2660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 28c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiTvClient; 29d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 30d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 32d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 34ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 35119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 36a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 3742c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 3867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 4078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 41e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 4238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 4378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 4438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 478b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 4878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 494893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 51a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 5602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 57a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 630792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 640792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 6578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 6678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 6778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 68d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 70d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 74d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 75ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 76ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 77ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 78ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 79d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 82d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 8702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 8902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 9002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 9102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 9202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 9302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 9402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 9538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 9638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 9738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 9838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 9938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 10038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 10138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 10238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 10338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 10438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 10538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 10638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 10738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 10838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 10938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 11878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 11978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 12078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 12378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 12478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 12578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 12778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 12878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 12978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1304893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 13178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 13278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 13378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1364893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1396d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1404893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 144119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim // List of records for vendor command listener to handle the the caller killed in action. 145119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 146119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 147119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 148119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 15592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 15692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 15792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 15892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 15992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1614d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1644d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 1654d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 166ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 168ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 169ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 170ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 172ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 173ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1770792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1790792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 1850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 1860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 18738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 18838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 18938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 190c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 19138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 19238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 19338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 19438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 1970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 1980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 1990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2020792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2032f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 204c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 205e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 2068b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 2073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 208347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 209347a60449981fc934e5a84122df87c1447665548Yuncheol Heo mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, 210347a60449981fc934e5a84122df87c1447665548Yuncheol Heo HdmiTvClient.ENABLED); 211347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 212c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, 213347a60449981fc934e5a84122df87c1447665548Yuncheol Heo HdmiTvClient.ENABLED); 2143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 215a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 219e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mPortInfo = initPortInfo(); 2248692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 22563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 22638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 22738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 22838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 22938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 23038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 23138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 23238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 23338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 23463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 23563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 23692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim mHdmiControlEnabled = true; 2374d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // TODO: Get control flag from persistent storage 2384d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = false; 2390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 240e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 241a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private void initializeLocalDevices(final List<Integer> deviceTypes) { 243a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 2453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 2463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 24713c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim mCecController.clearLogicalAddress(); 2483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 2493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 2503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 2513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 2523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 2533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 2543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 255c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 2563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 2573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 2583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 2593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 2603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 2613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 2623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 2633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 2653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2664893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 2670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 268c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 269c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 27038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 2723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 2753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 278a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 280a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 2823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 2833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 28413c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim device.handleAddressAllocated(address); 2853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2880340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 2890340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 290a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> initPortInfo() { 292a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 2940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 2960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 2970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 2980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 2990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 3010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.emptyList(); 3020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; 3050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mMhlController != null) { 3060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // TODO: Implement plumbing logic to get MHL port information. 3070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mhlPortInfo = mMhlController.getPortInfos(); 3080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Use the id (port number) to find the matched info between CEC and MHL to combine them 3110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. 3120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 3130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < cecPortInfo.length; ++i) { 3140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo cec = cecPortInfo[i]; 3150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int id = cec.getId(); 3160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim boolean mhlInfoFound = false; 3170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo mhl : mhlPortInfo) { 3180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (id == mhl.getId()) { 3190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), 3200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); 3210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mhlInfoFound = true; 3220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim break; 3230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (!mhlInfoFound) { 3260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(cec); 3270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(result); 3310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 3340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 3350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 3360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 3370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 3380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 3390340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 3400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mPortInfo is an unmodifiable list and the only reference to its inner list. 3410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // No lock is necessary. 3420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 3430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (portId == info.getId()) { 3440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return info; 3450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return null; 3480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 350e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 351401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 352401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 353401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 354401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 355401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 356401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 357401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 358c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 359401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 360401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 361401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 362401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 363401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 364401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 365401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 366401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 367401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 368401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 369401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 370c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 371401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 372401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portAddress == info.getAddress()) { 373401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return info.getId(); 374401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 375401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 376c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PORT_ID; 377401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 378401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 379401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 380e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 381e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 382e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 383e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 384e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 385e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 386e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 387e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 388e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 389e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 390e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 391e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 392e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 393e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 394e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 39567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 396e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 397c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 398c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 3993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 4003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 4023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 4033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 4063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 4073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 4093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 4103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 412a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 413a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 4140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 41579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 41679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 41779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 41879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 41979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 420a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 421a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 4223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 423092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 424092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 425092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 426092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 427092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 428092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 429092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 43060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 43160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 43260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 43360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiPortInfo portInfo : mPortInfo) { 43460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (hasSameTopPort(portInfo.getAddress(), physicalAddress) 43560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang && portInfo.isArcSupported()) { 43660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return true; 43760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 44060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 44160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 44279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 44367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 44467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 44567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 44663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 44763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 44863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 44963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 45063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 45163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 45263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 45363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 45463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 45563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 45667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 457c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 458c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 459c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 460d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 461c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 462a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 463d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 464a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 465d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 466d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 467d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 468a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 469d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 470a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 471d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 472c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 473c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 474a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 475a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 476a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 477092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 478092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 479092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 48079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 48179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 48260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 48360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 484a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 485092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 486a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 487092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 48879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 489c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 490092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 491092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 492092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 49360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 494c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 4953a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 4963a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 497092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 498a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 499a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 50067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 50167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 50267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 5038b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 50467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 50567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 506a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 50767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 50860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 50979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 51079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 51160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 51260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 51367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 51467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 51502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 51602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 51702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 51802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 51902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 5201de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 5210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 52202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 5230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 52402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 525a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5261de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 5271de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 528a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5291de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 5301de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 5310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 5330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 534c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 5350f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 5360f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 5370f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 538c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 5390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 5400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 5410f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 54302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 54402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 54560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 54660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 54760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 54860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 54960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 55079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 55179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 55279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 55379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 55479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 55579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // TODO: Hook up with AudioManager. 5563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 558ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 559ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 560ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 561ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 562ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 563ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 5643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 56542c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 56642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 5673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 5683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 5693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 57178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 57278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 57378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 57478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 57578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 57678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 57778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 57878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 58078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 58178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 58278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 58378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 58478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 58578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 58878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 5896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 5906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 5916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 5936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 5946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 597ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 5986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 5996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 6006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 6016d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6026d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6036d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6046d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 605ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 60638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 607ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 608ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 609ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 610ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 611ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 612ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 613ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 614ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 615ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 616ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 617ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 618ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 619ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 620ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 621119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 622119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 623119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 624119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 625119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 626119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 627119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 628119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 629119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 630119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 631119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 632119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 633119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 634119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 635119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 636119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 637119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 63878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 63978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 64078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 64278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 64378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 64478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 64578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 6470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 6480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 6490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 65078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 6510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 65278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 65378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 65478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 655a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 656a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 657a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 658a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 659a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 66079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 661a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 662a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 663c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 664a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 665a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 666a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 667a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 668a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 669a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 670a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 671a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 672a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 673a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 674a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 675a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 676a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 677a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 678a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 679a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 680c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 681a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 682a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 6838333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 684a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 685a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 686a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 687a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 688a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 689a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void sendKeyEvent(final int keyCode, final boolean isPressed) { 690a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 691a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 692a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 693a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 694a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // TODO: sendKeyEvent is for TV device only for now. Allow other 695a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // local devices of different types to use this as well. 696a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 697a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 698a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 699a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 700a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 701a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim tv.sendKeyEvent(keyCode, isPressed); 702a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 703a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 704a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 705a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 706a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 7077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 70878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 7137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 71578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 71678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 71778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 71978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 7247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 72678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 72778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 72878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 73078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 7357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 73778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 73878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 73978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 74178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 7467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 74878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7496d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 7506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 7516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 7526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 7536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 7546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 755ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 7566d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 7576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 7596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 7616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 7626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 7636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 7646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 7656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 766ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 767ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 768ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 769ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 770ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 771ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 772ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 773ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 774e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 775ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 776ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 777ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 778ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 779ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 780ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 781ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 782ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 783ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 784ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return tv.getSystemAudioMode(); 785ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 786ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 787ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 788ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 789ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 790ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 791ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 792ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 793ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 794ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 795ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 796c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 797ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 798ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 799ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 800ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 801ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 802ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 803ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 804ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 805ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 806ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 807ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 808ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 809ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 810ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 811ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 812ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 813ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 814ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 815ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 816ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 81792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 81892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 8199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 8209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 8219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 8229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 8249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 8259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public List<HdmiCecDeviceInfo> getInputDevices() { 8269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 8279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 8289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 8299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 8309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 8319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 8329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 8349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 8369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 837160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setControlEnabled(final boolean enabled) { 83892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim enforceAccessPermission(); 83992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 84092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim mHdmiControlEnabled = enabled; 84192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 84292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // TODO: Stop the running actions when disabled, and start 84392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // address allocation/device discovery when enabled. 84492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (!enabled) { 84592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return; 84692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 84792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim runOnServiceThread(new Runnable() { 84892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 84992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim public void run() { 85092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 85192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (tv == null) { 85292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return; 85392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 854c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int value = enabled ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED; 855c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, value); 856160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 857c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mMhlController.setOption(HdmiTvClient.OPTION_MHL_ENABLE, value); 858160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 8595344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim tv.launchRoutingControl(false); 86092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 86192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim }); 86292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 863a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 864a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 86541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 86641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 86741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 86841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 86941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 87041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 87141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 87241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 87341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 87441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 87541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 87641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 87741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 87841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 87941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 88041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 88141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 88241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 88341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 88441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 88541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 88641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 88741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 88841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 88941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 89041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 89141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 89241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 89341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 89441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 89541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 89641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 89741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 898a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 899a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 900a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 901a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 902a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 903a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 904a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 90538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 906a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 907a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 908a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 909a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 910a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 911160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 912160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 913160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setOption(final int key, final int value) { 9144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 915160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (!isTvDevice()) { 916160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return; 917160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 918160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim switch (key) { 919c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP: 920160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(key, value); 921160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 922c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF: 923160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // No need to pass this option to HAL. 924c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim tv().setAutoDeviceOff(value == HdmiTvClient.ENABLED); 925160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 926c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_INPUT_SWITCHING: // Fall through 927c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_POWER_CHARGE: 928160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 929160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(key, value); 930160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 931160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 932160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 933160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 934160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 935160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim private boolean isTvDevice() { 936160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return tv() != null; 937160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 9384d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 9394d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @Override 9404d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 9414d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 9424d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 9434d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 9444d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 9454d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 9464d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 947119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 948119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 949119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 950119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 951119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 952119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 953119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 954119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 955119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 956119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 957119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 958119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 959119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 960119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 961119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 962119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 963119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 964119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 965119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 966119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 967119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 968119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 969119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 970119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 971119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 972119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 973119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 974119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 975119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 976119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 977119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 978119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 979119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 980119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 981119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 982119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 98378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 98478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 985a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 98679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 98779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 98879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 9897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 9907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 991c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 9927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 9937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 99479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 99578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 99678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 997a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 99879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 99979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 100079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 10017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 10027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1003c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 10047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 10057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 100679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 100778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 100878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 100978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 101078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 101178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 101278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 101378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 101478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 101578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 101678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 101778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 101878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 101978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 102078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 102178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 102278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 102378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 102478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 102578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 102678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 102778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 102878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 102978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 103078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 103178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 103278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 103378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 103478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 10366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 10374893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 10384893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 10394893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 10404893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 10414893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 10424893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 10434893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 10446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 10454893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 10464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 10474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 10484893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 10494893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 10504893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 10514893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 10524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 10534893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 10544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 10554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 10564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 10576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1062ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1063ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1064ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1065ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1066ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1067ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1068ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1069ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1070ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1071ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1072ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1073ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1074ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1075ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1076ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1077ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1078ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1079ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1080ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1081ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1082ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1083ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1084ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1085ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1086ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1087ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1088ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1089ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1090ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 10919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 10929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 10939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 10949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 10959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 10969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 11019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 11029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 11039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 11049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 11059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 11069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 11079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 11089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 11109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim void invokeInputChangeListener(int activeAddress) { 11149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 11159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 11169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress); 11179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 11189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener.onChanged(activeSource); 11199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 11209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 11219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 11277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 11287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 11297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 11307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 11317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 113363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1134ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1135ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1136ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1137ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1138ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1139ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1140ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1141ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1142ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 11434893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 11444893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 114560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 114660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 11474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 114860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 114960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 115060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 115160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 11524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 115360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 115460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 115560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 115660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 115760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 115860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1159e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1160e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 116160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 1162c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (path1 & Constants.ROUTING_PATH_TOP_MASK) 1163c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim == (path2 & Constants.ROUTING_PATH_TOP_MASK); 116460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 116560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 116679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 1167c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV); 116879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 116979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 117079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1171c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 1172c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK); 117360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1174a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1175a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1176a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1177a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 117892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 117992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 118092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 118192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 118292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 118392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 118438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 118538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 118638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 118738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 118838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 118938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1190c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1191c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 119238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 119338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 119438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1195c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1196c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 119738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 119838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 119938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1200c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 120138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 120238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 120338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 120438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 120538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 120638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 120738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 120838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 120938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 121038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 121138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 121238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 121338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 121438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 121538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 121638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 121738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 121838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 121938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 122038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 122138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 122238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 122338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 122438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1225c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 122638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1227c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.ENABLED); 122838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo initializeLocalDevices(mLocalDevices); 122938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 123038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 123138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 123238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 123338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 123438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 123538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 123638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 123738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1238c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 123938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 124038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo device.onTransitionToStandby(mStandbyMessageReceived); 124138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 124238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 124338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 124438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 124538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * Called when there are the outstanding actions in the local devices. 124638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * This callback is used to wait for when the action queue is empty 124738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * during the power state transition to standby. 124838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 124938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 125038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void onPendingActionsCleared() { 125138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1252c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 125338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 125438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1255c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 125638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 125738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo device.onStandBy(mStandbyMessageReceived); 125838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 125938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 1260c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.DISABLED); 126138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1263119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1264119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1265119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1266119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1267119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1268119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1269119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1270119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1271119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1272119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1273119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1274119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1275119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1276119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1277119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1278119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1279119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1280119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1281119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1282119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1283119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1284119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1285119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1286119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1287119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1288119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1289119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1290119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1291119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 12924d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 12934d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 12944d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 12954d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12964d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 12984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 12994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 13004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 13014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 13024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 13030792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1304