HdmiControlService.java revision 87f22a2870ac363a5849a7252c1bd44ce2b809c2
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 19ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; 20ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 3138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 327ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 37c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 387d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 3960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 41d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 42d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 44d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 4612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 47ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 48119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 49a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 5142c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 55e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 5638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 5778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 5838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 597d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 605008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 617ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 627d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 640792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 668b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 6778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 684893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 70a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 727e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 75b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 76b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 7778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 78f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 81a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 830792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 89c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 9078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 91fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 92fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 93fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 94fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 95fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 96fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 97d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 98d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 99d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 100d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 101d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 102d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 103d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 104ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 110d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 112d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 113d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 11402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 11502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 11602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 11702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 11802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 11902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 12002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 12102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 12202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 12402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 12502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 12638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 12738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 12838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 12938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 13038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 13138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 13238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 13338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 13538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 13638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 13738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 13838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 14978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 15078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 15178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 15478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 15578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 15678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 15878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 15978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 16078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1614893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 16278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 16378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 16478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1674893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1696d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1714893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1736d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim // List of records for vendor command listener to handle the the caller killed in action. 176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 177119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 178119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 179119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 186b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 18712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private IHdmiRecordListener mRecordListener; 188b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 189b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 19012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 191b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 19292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 19392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 19492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 19592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 19692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 20308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo // Set to true while the input change by MHL is allowed. 20408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo @GuardedBy("mLock") 20508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo private boolean mMhlInputChangeEnabled; 20608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 207ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @GuardedBy("mLock") 208ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 209ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 210ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 211ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 212ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 213ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 214ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 215ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 216ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 217ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 2230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 2280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2332b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 23430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2352b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2362b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 23730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2382b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 23975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 24075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 24238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 24338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 244c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 24538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 24638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 24738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 24838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 249fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 250fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 251fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 252867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 253867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 254867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2577d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2617d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2627d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2637d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2647d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2657d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2667d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2687d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 2697d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 2707d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2717d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2727d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 2737d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2747d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 2750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2772f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 278c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2797ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2807ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 28108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 2828b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 283a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 285347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 2865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 287347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 288a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 289a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 290fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 291a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 292a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 296e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3002b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim initPortInfo(); 301ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 30275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 3038692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 30463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 30538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 30638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 30738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 30838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 30938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 31038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 31138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3127ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 31338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 31425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 31525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 31625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 31725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private void onInitializeCecComplete() { 318fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 319fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 320fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 321fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 322fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 32325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim registerContentObserver(); 32625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 32725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 32825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 3295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 3305008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 3315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 3325008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 3335008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 3345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 3355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 3365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 3375008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 3385691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 3395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 3405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 3415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 3455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 3465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 3475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 3505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 3515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 3525008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 3535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 3545008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 3555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 3565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 3585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 3595008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 3605008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 3625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 3635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 3645008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 36608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 3675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 36908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 37008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 37108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 3725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3735008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3755008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3765008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 3785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 3795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3805008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3817ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 3827ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 3847ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 3857ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 3867ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 3877ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3885008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 3895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void unregisterSettingsObserver() { 3925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); 3930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 394e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 395fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 3965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 397fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeLocalDevices(mLocalDevices, initiatedBy); 398a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 399a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 400a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 401fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeLocalDevices(final List<Integer> deviceTypes, final int initiatedBy) { 402a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 4043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 405fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final int[] finished = new int[1]; 4064b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo clearLocalDevices(); 4073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 4083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 4093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 4103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 4113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 414c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 4153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 4163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 417410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 418410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 419410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 420410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 4213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 4223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 4233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 4243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 4253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4274893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 428fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 429fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 430fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 4313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 437a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 438fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 439a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 4413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 4423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 443fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 4443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 4480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 449a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4502b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 451a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 4530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 4550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 4560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 4570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 4580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 4602b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 4612b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4622b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 46330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 46430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 4652b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 46630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 46730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 4680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 46930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 47030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 4710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 472f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 473f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 474f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 475f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 476f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 477f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 478f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 479f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 480f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 481f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 4820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 484f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 485f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 486f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 487f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 488f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 489f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 490f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 491f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 492f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 4932b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 494f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 4952b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 4990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 5000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 5010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 5020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 5030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 5040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 5052b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 5060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 508e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 509401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 510401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 511401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 512401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 513401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 514401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 515401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 516c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 517401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 518401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 519401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 520401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 521401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 522401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 523401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 524401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 525401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 526401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 527401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 528c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 5292b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 530401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 531401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 53209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 5332b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 53409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 53509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 536401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 537e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 538e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 539e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 540e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 541e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 542e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 543e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 544e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 545e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 546e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 547e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 548e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 549e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 550e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 551e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 55267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 553e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 554c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 555c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 5563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 5573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 5593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 5603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 5633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 5643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 5663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 5673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 569a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 57061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 5710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 57279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 57379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 57479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 57579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 5768960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return tv.getCecDeviceInfo(logicalAddress); 577a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 578a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 5793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 580092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 581092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 582092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 583092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 584092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 585092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 586092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 58760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 58960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 5902b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 5912b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 5922b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 59360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 59460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 59560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 59660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 59779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 59867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 59967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 60067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 60163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 60263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 60363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 60463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 60563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 60663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 60763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 60863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 60963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 61063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 61167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 612c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 613c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 614c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 615d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 616c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 617a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 618d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 619a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6205f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (mMessageValidator.isValid(command)) { 6215f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 6225f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 6235f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang Slog.e(TAG, "Invalid message type:" + command); 6245f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 6255f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 6265f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 6275f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 628d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 629d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 630a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 631d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 632a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6335f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 634c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 635c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 6367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6377df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command) { 6387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang sendMhlSubcommand(portId, command, null); 6407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command, SendMessageCallback callback) { 6447df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6457df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang mMhlController.sendSubcommand(portId, command, callback); 6467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6477df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6486aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 6496aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 6506aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 6516aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 6526aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 6536aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 6546aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 6556aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 6566aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 6576aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 6586aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 6596aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 660a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 661a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 662a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 66375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 66475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 66575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 666092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 667092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 668092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 66979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 67079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 67160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 67260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 673a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 674092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 675a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 676092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 67779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 678c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 679092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 680092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 681092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 68260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 683c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 6843a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 6853a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 686092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 687a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 688a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 68967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 69067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 69167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 692ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 69367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 69467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 695a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 696ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 69760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 69879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 699ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 70060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 701ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 70267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 70367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 70402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 70502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 70602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 70702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 70802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 7091de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 7100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 71102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 7120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 71302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 714a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7151de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 7161de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 717a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7181de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 7191de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 7200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 7220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 723c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 7240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 7250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 7260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 727c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 7280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 7290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 7300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 73202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 73302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 73460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 73560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 73660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 73760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 73860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 73979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 74079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 74179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 74279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 74379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 744b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 745b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 746b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 747b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 748b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 749b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 750b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 751b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 752b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 753b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 754b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 755b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 756b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 757b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 758b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 759b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 7603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 762ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 763ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 764ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 765ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 766ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 767ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 768410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 76942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 77042c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 77161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 7722b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 7732b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 7743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7767df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 7777df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang boolean handleMhlSubcommand(int portId, HdmiMhlSubcommand message) { 7787df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 7797df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 7807df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 7817df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 7827df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return device.handleSubcommand(message); 7837df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7847df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists[portId:" + portId + ", message:" + message); 7857df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return false; 7867df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7877df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 7887df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 7897df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 7907df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 7917df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 7927df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice newDevice = new HdmiMhlLocalDevice(this, portId); 7937df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice oldDevice = mMhlController.addLocalDevice(newDevice); 7947df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 7957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 7967df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 7977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 7997df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId); 8007df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 802ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // There is no explicit event for device removal unlike capability register event 803ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // used for device addition . Hence we remove the device on hotplug event. 804ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 805ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim updateSafeMhlInput(); 8067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 8087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8097df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 810ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 8117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlCbusModeChanged(int portId, int cbusmode) { 8157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8177df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCbusMode(cbusmode); 8197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for cbus mode change[portId:" + portId + 8217df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang ", cbusmode:" + cbusmode + "]"); 8227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlVbusOvercurrent(int portId, boolean on) { 8277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8287df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8297df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onVbusOvercurrentDetected(on); 8317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for vbus overcurrent event[portId:" + portId + "]"); 8337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 837ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void handleMhlCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { 8387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 840ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 841ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // Hotplug event should already have been called before capability register change event. 8427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCapabilityRegister(adopterId, deviceId); 844ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE); 845ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim updateSafeMhlInput(); 8467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8477df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for capability register change event[portId:" 8487df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 8497df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8517df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 852ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 853ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 854ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 855ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 856ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim SparseArray<HdmiMhlLocalDevice> devices = mMhlController.getAllLocalDevices(); 857ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 858ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiMhlLocalDevice device = devices.valueAt(i); 859ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 860ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 861ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 862ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 863ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 864ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 865ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 866ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 867ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 868ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 869ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 870ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 871ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 872ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 873ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 874ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 875ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 87678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 87778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 87878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 87978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 88078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 88178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 88278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 88378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 88478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 88578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 88678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 88778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 88878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 88978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 89078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 89178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 89278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 89378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 8946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 8956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 8966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 8986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 8996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9016d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 902ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 9036d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 9046d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 9056d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 9066d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 910ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 91138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 912ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 913ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 914ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 915ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 916ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 917ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 918ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 919ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 920ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 921ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 922ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 923ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 924ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 925ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 926119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 927119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 928119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 929119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 930119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 931119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 932119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 933119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 934119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 935119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 936119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 937119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 938119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 939119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 940119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 941119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 942119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 94312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 944b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 945b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 946b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 94712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = null; 948b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 949b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 950b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 951b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 95278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 95378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 95478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 95578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 95678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 95778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 95878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 95978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 9600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 9610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 9620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 9630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 96478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 9650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 96678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 96878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 96961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 9707e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 9717e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 9727e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 9737e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 9747e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9757e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 9767e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 97761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 97861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 97961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 9807e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9817e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 98261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 98361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 9847e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9857e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 9867e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9877e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 9887e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 9898960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 990a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 991a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 992a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 993a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 99472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 99572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 99672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 99772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 99879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 999a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1000a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1001c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1002a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1003a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 100487f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim if (mMhlController != null) { 100587f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDeviceById(deviceId); 100687f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim if (device != null) { 100787f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 100887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // the connected mobile device, start routing control to switch ports. 100987f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // callback is handled by MHL action. 101087f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim device.turnOn(callback); 101187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim tv.doManualPortSwitching(device.getInfo().getPortId(), null); 101287f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 101387f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 101487f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 10158960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1016a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1017a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1018a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1019a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1020a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1021a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1022a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1023a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1024a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1025a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 102672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 102772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 102872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 102972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1030a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1031a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1032a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1033c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1034a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1035a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 10368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1037a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1038a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1039a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1040a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1041a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1042c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1043a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1044a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1045a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1046a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 10474612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mMhlController != null) { 10484612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(mActivePortId); 10494612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (device != null) { 10504612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang device.sendKeyEvent(keyCode, isPressed); 10514612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 10524612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10534612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10544612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 10554612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 10564612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 10574612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 10584612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 10594612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10604612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1061a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1062a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1063a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1064a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1065a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1066a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 10677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 106878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10697fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 10737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 107578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 107678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 107778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 10787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 107978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10817fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 10847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 108678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 108778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 108878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 10897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 109078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 10957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10967fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 109778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 109878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 109978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 110178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 11067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 110878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 11126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 11136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 11146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1115ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 11166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 11176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 11196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11206d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 11236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 11246d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 11256d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1126ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1127ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1128ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1129ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1130ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1131ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1132ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1133ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1134e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1135ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1136ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1137ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1138ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1139ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1140ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1141ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1142ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1143ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1144377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1145ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1146ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1147ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1148ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1149ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1150ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1151ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1152ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1153ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1154ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1155ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1156c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1157ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1158ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1159ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1162ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1165ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1166ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1168ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1169ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1170ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1172ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1173ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1174ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1175ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1176ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 117792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 117892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 11799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 11809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 11819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 11829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 118561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 11869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 11879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 11889c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 11899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1190ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1191ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1192ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1193ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1194ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 11959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 119941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 120041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 120141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 120241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 120341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 120441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 120541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 120641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 120741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 120841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 120941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 121041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 121141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 121241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 121341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 121441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 121541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 121641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 121741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 121841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 121941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 122041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 122141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 122241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 122341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 122441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 122541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 122641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 122741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 122841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 122941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 123041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 123141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1232a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1233a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1234a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1235a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1236a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1237a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1238a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 123938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1240a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1241a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1242a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1243a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1244a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1245160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1246160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 12474d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 12484d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 12494d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 12504d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 12514d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 12534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1254119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1255119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1256119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1257119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1258119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1259119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1260119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1261119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1262119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1263119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1264119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 1265119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1266119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1267119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1268119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1269119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1270119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1271119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1272119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1273119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1274119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1275119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1276119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1277119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1278119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1279119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1280119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1281119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1282119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1283119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1284119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1285119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1286119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1287119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1288119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 128912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1290a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1291a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 129212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 129312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1294b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1295b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1296b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1297b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1298b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1299b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1300b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1301b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1302b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1303b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1304b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1305b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1306b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1307b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1308b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1309b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1310b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1311b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1312b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1313b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1314b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1315b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1316b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1317b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1318b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1319b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1320b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1321b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1322a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1323a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1324a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1325b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1326b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1327b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1328b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1329b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1330b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1331b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1332b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1333b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1334b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1335b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1336b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1337bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1338bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1339bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1340b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1341b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1342b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1343b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1344b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1345b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1346b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1347b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1348b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1349b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1350b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1351b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1352a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 135378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 135478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1355a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 135679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 135779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 135879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 13597fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 13607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1361c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 13627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 13637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 136479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 136578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 136678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1367a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 136879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 136979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 137079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 13717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 13727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1373c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 13747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 13757fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 137679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 137778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 137878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 137978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 138078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 138178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 138278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 138378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 138478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 138578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 138678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 138778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 138878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 138978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 139078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 139178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 139278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 139378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 139478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 139578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 139678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 139778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 139878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 139978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 140078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 140178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 140278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 140378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 140478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 14057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 14066d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 14074893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 14084893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 14094893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 14104893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14114893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 14124893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 14134893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 14154893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 14164893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 14174893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14194893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 142061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 14214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 14224893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 14234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 142461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang listener.onStatusChanged(device, status); 14254893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 14276d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14286d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14296d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14306d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1432ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1433ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1434ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1435ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1436ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1437ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1438ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1439ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1440ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1441ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1442ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1443ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1444ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1445ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1446ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1447ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1448ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1449ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1450ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1451ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1452ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1453ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1454ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1455ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1456ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1457ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1458ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1459ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1460ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 14619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 14629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 14639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 14649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 14669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14689c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14699c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 14709c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 14719c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14729c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 14739c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 14749c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 14759c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 14769c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 14779c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 14789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 14809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 148361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 14849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 14869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 148772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mInputChangeListener.onChanged(info); 14889c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 14899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 14909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 149512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1496b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 149712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(); 1498b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 149912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1500b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 150112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1502b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 150312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = listener; 1504b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1505b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1506b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1507b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1508b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 150912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 151012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 151112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return mRecordListener.getOneTouchRecordSource(recorderAddress); 151212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 151312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1514b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1515b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1516b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1517b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1518b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1519b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 152012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 152112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 152212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 152312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 152412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onOneTouchRecordResult(result); 152512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 152612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 152712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 152812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 152912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 153012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 153112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 153212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 153312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 153412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 153512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 153612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onTimerRecordingResult(result); 153712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1538e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1539e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1540e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1541e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1542e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1543e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1544e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1545e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1546e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (mRecordListener != null) { 1547e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1548e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mRecordListener.onClearTimerRecordingResult(result); 1549e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1550e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 155112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 155212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 155312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 155412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 155512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 15567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 15577fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 15587fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 15597fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 15607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 15617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 15627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 156363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1564ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1565ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1566ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1567ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1568ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1569ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1570ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1571ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1572ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 15734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 15744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 157560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 157660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 15774893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 157860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 157960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 158060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 158160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 15824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 158360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 158460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 158560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 158660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 158760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 158860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1589e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1590e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 159179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 159261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 159379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 159479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1595e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1596e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1597e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1598e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 159979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1600c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 160161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 160260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1603a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1604a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1605a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1606a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 160792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 160892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 160992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 161092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 161192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 161292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 161338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 161438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 161538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 161638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 161738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 161838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1619c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1620c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 162138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 162238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 162338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1624c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1625c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 162638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 162738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 162838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1629c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 163038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 163138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 163238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 163338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 163438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1635fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 163638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 163738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 163838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 163938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 164038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 164138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 164238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 164338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 164438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 164538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 164638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 1647c12035cd40d01b032013f515cb509e6c8791cf65Jeff Brown pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 164838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 164938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 165038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 165138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 16522849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo void nap() { 16532849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 16542849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo pm.nap(SystemClock.uptimeMillis()); 16552849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo } 16562849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo 165738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 165838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 165938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1660c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 166138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1662a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1663fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1664fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1665fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1666fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1667fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1668a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 166938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 167038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 167138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 167338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 167538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 167638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 167738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1678c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 16794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 16814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 16824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 16834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 16844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 16854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 16864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 16874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 16884b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 16894b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 16904b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 16914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 16944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 169738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 16984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 169938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim if (isTvDevice()) { 17015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim unregisterSettingsObserver(); 17025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 170338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 170438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 170538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 17064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 17074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 17094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 17104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 17124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 17134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 17164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 171738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 17184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 17194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1720c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 172138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 172238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1723c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 172438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 17254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 172638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 172738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 17285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 172938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17304d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1731119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1732119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1733119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1734119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1735119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1736119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1737119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1738119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1739119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1740119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1741119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1742119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1743119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1744119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1745119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1746119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1747119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1748119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1749119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1750119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1751119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1752119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1753119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1754119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1755119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1756119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1757119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1758119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1759119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 17604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 17614d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 17624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 17634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17644d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17654d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 17664d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 17674d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 17684d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 17694d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17704d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 17735008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setOption(int key, int value) { 17745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 17755008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 17765008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 17775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 17785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 17795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 17804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17825008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 17835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 17844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 17855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 17864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 17894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 17904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1793fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 17944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 17954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 17964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 17974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 17984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 18004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 18024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1804867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 1805867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 1806867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 1807867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 1808867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 1809867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 181008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 181108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo void setMhlInputChangeEnabled(boolean enabled) { 181208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 181308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 181408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 181508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 181608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 181708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 181808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 181908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 182008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 182108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 182208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 182308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 182408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 182508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 18260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1827