HdmiControlService.java revision 08a1be81d7b597f858164fee6a4934264259b3ae
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 195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 2938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 307ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 35c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 367d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 3760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 39d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 40d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 42d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 4412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 45ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 46119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 47a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 4942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 53e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 5438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 5578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 5638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 577d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 597ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 607d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 612b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 648b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 6578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 664893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 68a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 707e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 73b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 74b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 7578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 76f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 7802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 79a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 830792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 87c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 8878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 89fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 90fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 91fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 92fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 93fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 94fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 95d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 96d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 97d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 98d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 99d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 100d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 101d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 102ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 108d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 109d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 110d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 11202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 11302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 11402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 11502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 11602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 11702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 11802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 11902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 12002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 12202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 12302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 12438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 12538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 12638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 12738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 12838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 12938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 13038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 13138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 13338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 13438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 13538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 13638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 13838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1450792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 14778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 14878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 14978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 15278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 15378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 15478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 15678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 15778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 15878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 16078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 16178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 16278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1654893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1694893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 173119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim // List of records for vendor command listener to handle the the caller killed in action. 174119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 177119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 184b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 18512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private IHdmiRecordListener mRecordListener; 186b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 187b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 18812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 189b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 19092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 19192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 19292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 19392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 19492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1954d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1964d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 20108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo // Set to true while the input change by MHL is allowed. 20208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo @GuardedBy("mLock") 20308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo private boolean mMhlInputChangeEnabled; 20408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 205ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 206ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 207ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 208ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 209ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 210ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 211ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 212ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2134893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 2180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 2230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2282b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 22930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2302b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2312b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 23230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2332b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 23475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 23575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 23638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 23738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 23838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 239c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 24038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 24138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 24238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 24338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 244fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 245fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 246fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 247867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 248867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 249867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2500792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2510792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2527d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2567d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2577d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2587d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2597d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2607d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2617d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2627d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2637d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 2647d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 2657d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2667d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 2687d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2697d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 2700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2710792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2722f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 273c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2747ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2757ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 27608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 2778b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 278a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 280347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 2815008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 282347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 283a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 284a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 285fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 286a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 287a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 291e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2952b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim initPortInfo(); 29675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 2978692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 29863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 29938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 30038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 30138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 30238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 30338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 30438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 30538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3067ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 30738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 30825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 30925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 31025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 31125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private void onInitializeCecComplete() { 312fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 313fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 314fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 315fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 316fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 31725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim registerContentObserver(); 32025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 32125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 32225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 3235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 3255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 3265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 3275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 3285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 3295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 3305008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 3315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 3325008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 3335008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim for (String s: settings) { 3345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 3355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 3365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3375008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 3405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 3415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 3425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 3455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 3465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 3475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 3485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 3495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 3505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 3515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3525008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 3535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 3545008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 3555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 3575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 3585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 3595008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3605008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 36108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 3625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 36408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 36508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 36608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 3675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3705008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 3735008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 3745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3755008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3767ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 3777ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 3797ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 3807ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 3817ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 3827ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 3845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void unregisterSettingsObserver() { 3875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); 3880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 389e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 390fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 3915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 392fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeLocalDevices(mLocalDevices, initiatedBy); 393a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 394a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 395a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 396fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeLocalDevices(final List<Integer> deviceTypes, final int initiatedBy) { 397a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 3993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 400fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final int[] finished = new int[1]; 4014b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo clearLocalDevices(); 4023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 4033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 4043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 4053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 4063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 409c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 4103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 4113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 412410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 413410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 414410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 415410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 4163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 4173ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 4183ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 4193ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 4203ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4224893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 423fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 424fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 425fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 4263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 432a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 433fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 434a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 4363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 4373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 438fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 4393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 4430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 444a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4452b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 446a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 4480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 4500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 4510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 4520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 4530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 4552b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 4562b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4572b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 45830c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 45930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 4602b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 46130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 46230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 4630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 46430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 46530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 4660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 467f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 468f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 469f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 470f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 471f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 472f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 473f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 474f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 475f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 476f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 4770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 479f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 480f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 481f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 482f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 483f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 484f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 485f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 486f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 487f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 4882b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 489f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 4902b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 4940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 4950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 4960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 4970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 4980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 4990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 5002b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 5010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 503e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 504401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 505401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 506401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 507401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 508401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 509401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 510401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 511c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 512401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 513401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 514401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 515401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 516401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 517401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 518401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 519401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 520401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 521401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 522401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 523c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 5242b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 525401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 526401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 52709ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 5282b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 52909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 53009ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 531401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 532e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 533e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 534e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 535e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 536e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 537e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 538e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 539e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 540e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 541e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 542e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 543e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 544e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 545e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 546e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 54767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 548e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 549c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 550c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 5513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 5523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 5543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 5553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 5583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 5593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 5613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 5623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 564a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 56561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 5660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 56779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 56879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 56979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 57079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 57179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 572a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 573a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 5743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 575092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 576092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 577092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 578092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 579092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 580092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 581092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 58260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 58360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 58460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 5852b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 5862b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 5872b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 58960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 59060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 59160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 59279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 59367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 59467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 59567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 59663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 59763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 59863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 59963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 60063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 60163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 60263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 60363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 60463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 60563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 60667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 607c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 608c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 609c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 610d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 611c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 612a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 613d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 614a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6155f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (mMessageValidator.isValid(command)) { 6165f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 6175f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 6185f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang Slog.e(TAG, "Invalid message type:" + command); 6195f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 6205f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 6215f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 6225f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 623d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 624d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 625a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 626d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 627a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6285f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 629c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 630c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 6317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command) { 6337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang sendMhlSubcommand(portId, command, null); 6357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6377df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command, SendMessageCallback callback) { 6397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang mMhlController.sendSubcommand(portId, command, callback); 6417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 6446aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 6456aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 6466aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 6476aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 6486aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 6496aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 6506aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 6516aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 6526aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 6536aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 6546aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 655a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 656a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 657a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 65875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 65975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 66075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 661092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 662092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 663092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 66479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 66579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 66660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 66760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 668a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 669092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 670a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 671092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 67279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 673c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 674092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 675092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 676092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 67760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 678c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 6793a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 6803a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 681092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 682a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 683a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 68467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 68567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 68667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 6878b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 68867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 68967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 690a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 69167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 69260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 69379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 69479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 69560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 69660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 69767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 69867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 69902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 70002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 70102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 70202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 70302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 7041de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 7050f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 70602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 7070f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 70802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 709a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7101de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 7111de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 712a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7131de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 7141de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 7150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 7170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 718c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 7190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 7200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 7210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 722c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 7230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 7240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 7250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 72702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 72802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 72960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 73060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 73160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 73260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 73360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 73479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 73579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 73679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 73879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 739b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 740b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 741b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 742b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 743b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 744b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 745b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 746b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 747b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 748b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 749b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 750b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 751b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 752b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 753b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 754b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 7553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 757ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 758ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 759ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 760ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 761ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 762ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 763410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 76442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 76542c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 76661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 7672b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 7682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 7693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7717df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 7727df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang boolean handleMhlSubcommand(int portId, HdmiMhlSubcommand message) { 7737df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 7747df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 7757df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 7767df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 7777df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return device.handleSubcommand(message); 7787df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7797df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists[portId:" + portId + ", message:" + message); 7807df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return false; 7817df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7827df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 7837df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 7847df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 7857df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 7867df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 7877df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice newDevice = new HdmiMhlLocalDevice(this, portId); 7887df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice oldDevice = mMhlController.addLocalDevice(newDevice); 7897df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 7907df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 7917df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 7927df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 7937df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 7947df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId); 7957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 7967df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 7977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 7987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 7997df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8007df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8037df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlCbusModeChanged(int portId, int cbusmode) { 8057df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCbusMode(cbusmode); 8097df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8107df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for cbus mode change[portId:" + portId + 8117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang ", cbusmode:" + cbusmode + "]"); 8127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlVbusOvercurrent(int portId, boolean on) { 8177df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onVbusOvercurrentDetected(on); 8217df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for vbus overcurrent event[portId:" + portId + "]"); 8237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { 8287df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8297df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang // Hot plug event should be called before capability register change event. 8317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCapabilityRegister(adopterId, deviceId); 8337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for capability register change event[portId:" 8357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 8367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8377df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 83978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 84078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 84178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 84278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 84378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 84478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 84578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 84678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 84778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 84878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 84978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 85078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 85178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 85278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 85378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 85478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 85578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 85678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 8576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 8586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 8596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 8616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 8626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 865ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 8666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 8676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 8686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 8696d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 873ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 87438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 875ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 876ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 877ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 878ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 879ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 880ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 881ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 882ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 883ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 884ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 885ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 886ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 887ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 888ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 889119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 890119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 891119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 892119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 893119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 894119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 895119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 896119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 897119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 898119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 899119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 900119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 901119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 902119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 903119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 904119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 905119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 90612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 907b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 908b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 909b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 91012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = null; 911b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 912b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 913b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 914b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 91578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 91678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 91778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 91878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 91978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 92078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 92178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 92278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 9230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 9240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 9250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 9260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 92778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 9280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 92978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 93078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 93178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 93261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 9337e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 9347e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 9357e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 9367e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 9377e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9387e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 9397e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 94061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 94161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 94261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 9437e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9447e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 94561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 94661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 9477e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9487e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 9497e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 9507e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 9517e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 952a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 953a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 954a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 955a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 956a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 95772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 95872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 95972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 96072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 96179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 962a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 963a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 964c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 965a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 966a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 967a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 968a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 969a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 970a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 971a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 972a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 973a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 974a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 975a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 976a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 977a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 97872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 97972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 98072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 98172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 982a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 983a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 984a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 985c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 986a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 987a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 9888333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 989a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 990a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 991a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 992a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 993a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 994c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 995a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 996a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 997a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 998a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 999c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 1000c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim if (localDevice == null) { 1001c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "Local device not available"); 1002a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1003a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1004c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim localDevice.sendKeyEvent(keyCode, isPressed); 1005a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1006a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1007a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1008a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1009a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 10107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 101178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 10167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 101878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 101978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 102078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 10217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 102278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 10277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 102978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 103078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 103178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 10327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 103378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 10387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 104078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 104178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 104278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 10437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 104478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 10467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 10477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 10487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 10497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10507fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 105178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 10536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 10546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 10556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 10566d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 10576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1058ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 10596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 10606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 10626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 10646d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 10656d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 10666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 10676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 10686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1069ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1070ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1071ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1072ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1073ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1074ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1075ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1076ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1077e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1078ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1079ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1080ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1081ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1082ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1083ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1084ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1085ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1086ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1087377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1088ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1089ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1090ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1091ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1092ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1093ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1094ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1095ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1096ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1097ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1098ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1099c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1100ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1101ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1102ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1103ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1104ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1105ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1106ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1107ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1108ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1109ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1110ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1111ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1112ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1113ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1114ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1115ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1116ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1117ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1118ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1119ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 112092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 112192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 11229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 11239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 11249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 11259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 112861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 11299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 11309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 11319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 11329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 11339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 11349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 11359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 11379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 11389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 11399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 114041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 114141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 114241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 114341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 114441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 114541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 114641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 114741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 114841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 114941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 115041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 115141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 115241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 115341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 115441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 115541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 115641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 115741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 115841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 115941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 116041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 116141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 116241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 116341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 116441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 116541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 116641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 116741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 116841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 116941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 117041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 117141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 117241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1173a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1174a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1175a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1176a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1177a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1178a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1179a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 118038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1181a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1182a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1183a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1184a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1185a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1186160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1187160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 11884d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 11894d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 11904d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 11914d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 11924d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 11934d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 11944d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1195119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1196119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1197119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1198119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1199119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1200119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1201119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1202119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1203119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1204119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1205119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 1206119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1207119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1208119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1209119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1210119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1211119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1212119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1213119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1214119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1215119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1216119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1217119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1218119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1219119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1220119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1221119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1222119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1223119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1224119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1225119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1226119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1227119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1228119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1229119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 123012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1231a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1232a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 123312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 123412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1235b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1236b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1237b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1238b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1239b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1240b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1241b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1242b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1243b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1244b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1245b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1246b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1247b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1248b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1249b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1250b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1251b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1252b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1253b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1254b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1255b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1256b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1257b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1258b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1259b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1260b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1261b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1262b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1263a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1264a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1265a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1266b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1267b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1268b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1269b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1270b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1271b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1272b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1273b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1274b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1275b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1276b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1277b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1278bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1279bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1280bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1281b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1282b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1283b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1284b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1285b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1286b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1287b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1288b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1289b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1290b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1291b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1292b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1293a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 129478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 129578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1296a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 129779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 129879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 129979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 13007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 13017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1302c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 13037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 13047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 130579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 130678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 130778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1308a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 130979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 131079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 131179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 13127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 13137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1314c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 13157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 13167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 131779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 131878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 131978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 132078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 132178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 132278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 132378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 132478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 132578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 132678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 132778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 132878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 132978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 133078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 133178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 133278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 133378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 133478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 133578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 133678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 133778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 133878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 133978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 134078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 134178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 134278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 134378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 134478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 134578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 13467fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 13476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 13484893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 13494893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 13504893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 13514893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 13524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 13534893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 13544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 13556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 13564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 13574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 13584893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 13594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 13604893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 136161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 13624893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 13634893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 13644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 136561daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang listener.onStatusChanged(device, status); 13664893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 13674893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 13686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13696d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1373ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1374ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1375ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1376ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1377ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1378ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1379ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1380ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1381ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1382ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1383ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1384ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1385ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1386ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1387ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1388ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1389ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1390ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1391ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1392ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1393ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1394ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1395ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1396ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1397ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1398ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1399ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1400ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1401ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 14029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 14039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 14049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 14059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 14079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 14119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 14129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 14149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 14159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 14169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 14179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 14189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 14199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 14219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 142461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 14259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 14269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 14279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 142872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mInputChangeListener.onChanged(info); 14299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 14309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 14319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 143612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1437b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 143812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(); 1439b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 144012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1441b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 144212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1443b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 144412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = listener; 1445b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1446b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1447b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1448b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1449b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 145012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 145112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 145212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return mRecordListener.getOneTouchRecordSource(recorderAddress); 145312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 145412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1455b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1456b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1457b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1458b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1459b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1460b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 146112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 146212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 146312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 146412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 146512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onOneTouchRecordResult(result); 146612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 146712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 146812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 146912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 147012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 147112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 147212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 147312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 147412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 147512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 147612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 147712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onTimerRecordingResult(result); 147812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1479e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1480e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1481e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1482e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1483e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1484e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1485e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1486e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1487e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (mRecordListener != null) { 1488e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1489e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mRecordListener.onClearTimerRecordingResult(result); 1490e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1491e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 149212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 149312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 149412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 149512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 149612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 14977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 14987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 14997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 15007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 15017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 15027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 15037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 150463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1505ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1506ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1507ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1508ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1509ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1510ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1511ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1512ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1513ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 15144893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 15154893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 151660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 151760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 15184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 151960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 152060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 152160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 152260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 15234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 152460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 152560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 152660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 152760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 152860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 152960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1530e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1531e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 153279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 153361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 153479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 153579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1536e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1537e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1538e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1539e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 154079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1541c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 154261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 154360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1544a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1545a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1546a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1547a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 154892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 154992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 155092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 155192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 155292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 155392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 155438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 155538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 155638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 155738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 155838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 155938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1560c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1561c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 156238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 156338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 156438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1565c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1566c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 156738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 156838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 156938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1570c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 157138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 157238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 157338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 157438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 157538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1576fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 157738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 157838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 157938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 158038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 158138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 158238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 158338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 158438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 158538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 158638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 158738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 158838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 158938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 159038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 159138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 159238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 15932849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo void nap() { 15942849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 15952849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo pm.nap(SystemClock.uptimeMillis()); 15962849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo } 15972849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo 159838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 159938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 160038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1601c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 160238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1603a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1604fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1605fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1606fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1607fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1608fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1609a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 161038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 161138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 161238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 161338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 161438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 161538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 161638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 161738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 161838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1619c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 16204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 16224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 16234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 16244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 16254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 16264fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 16274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 16284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 16294b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 16304b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 16314b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 16324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 16354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 163838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 16394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 164038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 16415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim if (isTvDevice()) { 16425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim unregisterSettingsObserver(); 16435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 164438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 164538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 164638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 16474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 16484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 16494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 16504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 16514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 16534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 16544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16564fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 16574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 165838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 16594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 16604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1661c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 166238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 166338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1664c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 166538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 16664fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 166738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 166838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 16695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 167038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 16714d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1672119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1673119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1674119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1675119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1676119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1677119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1678119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1679119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1680119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1681119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1682119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1683119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1684119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1685119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1686119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1687119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1688119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1689119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1690119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1691119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1692119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1693119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1694119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1695119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1696119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1697119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1698119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1699119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1700119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 17014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 17024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 17034d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 17044d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17054d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17064d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 17074d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 17084d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 17094d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 17104d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17114d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 17124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 17145008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setOption(int key, int value) { 17155008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 17165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 17175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 17185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 17195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 17205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 17214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 17245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 17254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 17265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 17274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17294fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 17304fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 17314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1734fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 17354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 17364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 17374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 17384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 17394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 17414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 17434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1745867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 1746867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 1747867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 1748867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 1749867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 1750867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 175108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 175208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo void setMhlInputChangeEnabled(boolean enabled) { 175308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 175408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 175508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 175608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 175708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 175808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 175908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 176008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 176108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 176208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 176308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 176408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 176508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 176608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 17670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1768