10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 19ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; 20ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 265b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SET_LANGUAGE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 305b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL; 315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 3338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 347ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 39c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 407d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 4160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 43d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 44d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 46d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 48b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kimimport android.hardware.hdmi.IHdmiMhlVendorCommandListener; 4912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 50ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 51119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 52a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 537fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager; 547fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager.TvInputCallback; 555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 5642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 60e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 6138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 6278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 6338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 647d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 667ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 718b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 7278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 74959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 76a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 787e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 81b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 82b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 83959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.FileDescriptor; 84959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.PrintWriter; 8578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 86f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 870340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 891ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 90a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 975fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale HONG_KONG = new Locale("zh", "HK"); 985fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale MACAU = new Locale("zh", "MO"); 990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 100c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 10178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 102fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 103fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 104fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 105fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 106fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 107b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo static final int INITIATED_BY_HOTPLUG = 4; 108fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 109d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 110d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 112d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 113d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 114d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 115d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 116ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 122d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 123d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 124d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 125d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 12602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 12802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 13002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 13102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 13202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 13302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 13402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 13602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 13702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1381ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 139f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 142f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 14438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 14538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 14638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 14738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 14938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 15038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 15138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 15238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1541ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1555fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim String language = getMenuLanguage(); 1561ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1571ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1581ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1591ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 16038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 16138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1625fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim 1635fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private String getMenuLanguage() { 1645fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim Locale locale = Locale.getDefault(); 1655fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { 1665fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Android always returns "zho" for all Chinese variants. 1675fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Use "bibliographic" code defined in CEC639-2 for traditional 1685fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Chinese used in Taiwan/Hong Kong/Macau. 1695fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return "chi"; 1705fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } else { 1715fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return locale.getISO3Language(); 1725fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 1735fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 17438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1770792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1790792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1800792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 18178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 18278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 18378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 18678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 18778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 18978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 19078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 19178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 192f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 1934893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 197f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 198119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 199119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 200119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 201119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 2029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 2039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 2049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 205b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 20612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 207b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 20892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 20992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 21092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 21192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 21292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 2134d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 2144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 2154d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2164d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2174d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2184d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 219ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 220ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 221ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 222ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 228f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 229f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 230f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2382b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 23930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2402b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2412b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 24230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2432b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 244e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 245e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 246e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 24775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 24875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 250c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 25138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 25238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2531ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2541ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2551ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 25638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 25738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 258fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 259fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 260fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 261867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 262867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 263867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 264f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 265f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 266f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 267f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 268b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim // List of records for MHL Vendor command listener to handle the caller killed in action. 269f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 270b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final ArrayList<HdmiMhlVendorCommandListenerRecord> 271b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords = new ArrayList<>(); 272f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 273f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 274f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 275f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 276f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 277781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim private HdmiMhlControllerStub mMhlController; 278f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 2797fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Nullable 2807fa3a66470d2133796defd14a0600578758882acJinsuk Kim private TvInputManager mTvInputManager; 2817fa3a66470d2133796defd14a0600578758882acJinsuk Kim 282e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim @Nullable 283e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private PowerManager mPowerManager; 284e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 285f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 286f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 287e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 288e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 289e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 290e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 291964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Set to true if the logical address allocation is completed. 292964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean mAddressAllocated = false; 293964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 294964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Buffer for processing the incoming cec messages while allocating logical addresses. 295964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private final class CecMessageBuffer { 296964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private List<HdmiCecMessage> mBuffer = new ArrayList<>(); 297964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 298964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void bufferMessage(HdmiCecMessage message) { 299964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim switch (message.getOpcode()) { 300964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 301964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferActiveSource(message); 302964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 303964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_IMAGE_VIEW_ON: 304964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_TEXT_VIEW_ON: 305964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferImageOrTextViewOn(message); 306964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 307964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Add here if new message that needs to buffer 308964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim default: 309964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Do not need to buffer messages other than above 310964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 311964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 312964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 313964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 314964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void processMessages() { 315964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (final HdmiCecMessage message : mBuffer) { 316964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim runOnServiceThread(new Runnable() { 317964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim @Override 318964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void run() { 319964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim handleCecCommand(message); 320964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 321964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim }); 322964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 323964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 324964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 325964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 326964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferActiveSource(HdmiCecMessage message) { 327964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) { 328964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 329964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 330964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 331964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 332964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferImageOrTextViewOn(HdmiCecMessage message) { 333964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) && 334964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) { 335964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 336964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 337964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 338964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 339964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Returns true if the message is replaced 340964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) { 341964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (int i = 0; i < mBuffer.size(); i++) { 342964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim HdmiCecMessage bufferedMessage = mBuffer.get(i); 343964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (bufferedMessage.getOpcode() == opcode) { 344964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.set(i, message); 345964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 346964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 347964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 348964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return false; 349964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 350964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 351964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 352964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(); 353964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 3540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 3550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 3567d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 3575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 3580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 3607d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 3617d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 3627d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 3637d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 3647d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 3657d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 3667d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 3677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 3687d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 3697d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3707d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3717d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 3727d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3737d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 3740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 3750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 3762f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 377c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 3787ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 3797ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 38008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 3818b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 382a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 3833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 384347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 3855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 386347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 387a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 388a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 389fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 390a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 391a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 3920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 39308f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim return; 3940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 396781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim mMhlController = HdmiMhlControllerStub.create(this); 397f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 3980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 3990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 400ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 401f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 402f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 40375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 4048692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 40563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 406f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 4070608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register broadcast receiver for power state change. 40838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 40938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 41038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 4111ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 4121ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 4130608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 4140608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register ContentObserver to monitor the settings change. 4150608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo registerContentObserver(); 41638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 4175b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); 4187ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 41938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 4207fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Override 4217fa3a66470d2133796defd14a0600578758882acJinsuk Kim public void onBootPhase(int phase) { 4227fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 4237fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager = (TvInputManager) getContext().getSystemService( 4247fa3a66470d2133796defd14a0600578758882acJinsuk Kim Context.TV_INPUT_SERVICE); 425e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 4267fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4277fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4287fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4297fa3a66470d2133796defd14a0600578758882acJinsuk Kim TvInputManager getTvInputManager() { 4307fa3a66470d2133796defd14a0600578758882acJinsuk Kim return mTvInputManager; 4317fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4327fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4337fa3a66470d2133796defd14a0600578758882acJinsuk Kim void registerTvInputCallback(TvInputCallback callback) { 4347fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4357fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.registerCallback(callback, mHandler); 4367fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4377fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4387fa3a66470d2133796defd14a0600578758882acJinsuk Kim void unregisterTvInputCallback(TvInputCallback callback) { 4397fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4407fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.unregisterCallback(callback); 4417fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4427fa3a66470d2133796defd14a0600578758882acJinsuk Kim 443e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim PowerManager getPowerManager() { 444e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return mPowerManager; 445e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 446e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 44725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 44825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 44925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 4500608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo private void onInitializeCecComplete(int initiatedBy) { 451fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 452fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 453fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 454fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 455fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 456de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 4575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 4580608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4590608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo int reason = -1; 4600608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo switch (initiatedBy) { 4610608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_BOOT_UP: 4620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; 4630608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4640608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_ENABLE_CEC: 4650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; 4660608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4670608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_SCREEN_ON: 4680608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_WAKE_UP_MESSAGE: 4690608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; 4700608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4710608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (reason != -1) { 4730608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(true, reason); 47425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 47525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 47625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 4775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 4785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 4795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 4805008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 4815008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 4825008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 4835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 4845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 4855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 4865691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 4875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 4885008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 4895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 4935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 4945008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 4955008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 497f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 4985008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 4995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 5005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 5015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 5025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 5035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 5045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 5055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 507de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 508de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim tv().setAutoWakeup(enabled); 509de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 510350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 5115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 513de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 514de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim tv().setAutoDeviceOff(enabled); 515de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 5165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 5175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 51908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 5205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 522f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 5235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 5295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 5305008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5327ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 5337ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 5357ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 5367ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 5377ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 5387ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 5405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 542fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 543964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = false; 5445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 5455b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(mLanguage)); 546b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo initializeLocalDevices(initiatedBy); 547a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 548a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 549a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 550b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void initializeLocalDevices(final int initiatedBy) { 551a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 552b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // A container for [Device type, Local device info]. 553b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 554b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (int type : mLocalDevices) { 5556f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 5566f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (localDevice == null) { 5576f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim localDevice = HdmiCecLocalDevice.create(this, type); 5586f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 5593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 560b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo localDevices.add(localDevice); 561b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 5626f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // It's now safe to flush existing local devices from mCecController since they were 5636f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // already moved to 'localDevices'. 5646f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim clearLocalDevices(); 565b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocateLogicalAddress(localDevices, initiatedBy); 566b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 567b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 568b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo @ServiceThreadOnly 569b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void allocateLogicalAddress(final ArrayList<HdmiCecLocalDevice> allocatingDevices, 570b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int initiatedBy) { 571b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo assertRunOnServiceThread(); 57289ec14e48f4a1bdf291cda9fba7b8172f55a2447Yuncheol Heo mCecController.clearLogicalAddress(); 573b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>(); 574b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int[] finished = new int[1]; 575964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = allocatingDevices.isEmpty(); 576964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 577b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (final HdmiCecLocalDevice localDevice : allocatingDevices) { 578b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo mCecController.allocateLogicalAddress(localDevice.getType(), 5793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 5803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 5813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 582c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 5833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 5843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 585410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 586410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 587410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 588410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 5893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 5903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 5913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 592b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocatedDevices.add(localDevice); 5933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5954893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 596b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (allocatingDevices.size() == ++finished[0]) { 597964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = true; 598b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (initiatedBy != INITIATED_BY_HOTPLUG) { 599b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // In case of the hotplug we don't call onInitializeCecComplete() 600b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // since we reallocate the logical address only. 6010608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo onInitializeCecComplete(initiatedBy); 602b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 603b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo notifyAddressAllocated(allocatedDevices, initiatedBy); 604964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.processMessages(); 6053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 6083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 611a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 612b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) { 613a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 614b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (HdmiCecLocalDevice device : devices) { 615b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int address = device.getDeviceInfo().getLogicalAddress(); 616fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 6173ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6183ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6193ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 6210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 622a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6232b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 624a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 6260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 6270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 6280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 6290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 6300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 6310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 6332b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 6342b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6352b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 63630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 63730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 638e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 6392b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 64030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 64130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 642e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 6430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 64430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 64530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 646e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 6470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 648f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 649f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 650f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 651f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 652f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 6530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 654f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 6550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 656f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 657f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 658f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 659f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 660f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 661f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 662f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 663f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 664f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 665f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 666f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 667f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 668f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 6692b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6702b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 671f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 6720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 6742738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 6752738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 6762738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 6772738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 6780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 6790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 6800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 6810340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 6820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 6830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 6840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 6852b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 6860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6870340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 688e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 689401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 690401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 691401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 692401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 693401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 694401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 695401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 696c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 697401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 698401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 699401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 700401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 701401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 702401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 703401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 704401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 705401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 706401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 707401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 708c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 7092b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 710401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 711401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 71209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 7132b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 71409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 71509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 716401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 717e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 718e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 719e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 720e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 721e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 722e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 723e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 724e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 725e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 726e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 727e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 728e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 729e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 730e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 731e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 73267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 733e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 734c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 735c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 7363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 7373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 7393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 7403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 7433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 7443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 7463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 7473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 749a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 75061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 7510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 752de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return tv() == null ? null : tv().getCecDeviceInfo(logicalAddress); 753a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 754a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 7556ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim @ServiceThreadOnly 7566ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiDeviceInfo getDeviceInfoByPort(int port) { 7576ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim assertRunOnServiceThread(); 7586ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiMhlLocalDeviceStub info = mMhlController.getLocalDevice(port); 7596ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim if (info != null) { 7606ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return info.getInfo(); 7616ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7626ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return null; 7636ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7646ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim 7653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 766092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 767092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 768092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 769092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 770092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 771092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 772092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 77360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 77460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 77560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 776339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 7772b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 7782b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 77960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 78060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 78160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 78260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 78379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 78467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 78567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 78667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 78763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 78863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 78963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 79063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 79163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 79263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 79363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 79463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 79563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 79663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 79767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 798c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 799c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 800c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 801d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 802c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 803a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 804d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 805a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8064c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) { 8075f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 8085f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 8092e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.error("Invalid message type:" + command); 8105f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 8115f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 8125f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 8135f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 814d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 815d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 816a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 817d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 818a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8195f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 820c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 821c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 8226aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 8236aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 8246aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 8256aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 8266aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 8276aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 8286aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 8296aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 8306aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 8316aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 8326aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 8336aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 834a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 835a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 836a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 837964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!mAddressAllocated) { 838964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.bufferMessage(message); 839964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 840964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 8414c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int errorCode = mMessageValidator.isValid(message); 8424c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode != HdmiCecMessageValidator.OK) { 843a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // We'll not response on the messages with the invalid source or destination 844a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // or with parameter length shorter than specified in the standard. 8454c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode == HdmiCecMessageValidator.ERROR_PARAMETER) { 8464c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); 8474c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo } 8484c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return true; 84975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 850092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 851092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 852092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 8531481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim void setAudioReturnChannel(int portId, boolean enabled) { 8541481a4282818939436f590d8c88aea2d19166b8eJinsuk Kim mCecController.setAudioReturnChannel(portId, enabled); 85560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 85660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 857a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 858092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 859a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 860092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 86179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 862c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 863092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 864092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 865092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 86660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 867c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 8682e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unhandled cec command:" + message); 8693a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 870092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 871a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 872a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 87367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 87467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 87567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 876ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 87767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 87867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 879a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 880ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 88160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 882b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 883b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (connected && !isTvDevice()) { 884b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 885b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo for (int type : mLocalDevices) { 886b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 887b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (localDevice == null) { 888b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice = HdmiCecLocalDevice.create(this, type); 889b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice.init(); 890b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo } 891b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevices.add(localDevice); 892b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 893b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); 894b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 895b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 89679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 897ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 89860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 899ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 90067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 90167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 90202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 90302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 90402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 90502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 90602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 9071de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 9080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 90902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 9100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 91102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 912a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 9131de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 9141de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 915a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 9161de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 9171de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 9180f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 9200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 921c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 9220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 9230f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 9240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 925c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 9260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 9270f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 9280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 93002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 93102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 93260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 93360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 93460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 93560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 93660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 93779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 93879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 93979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 94079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 94179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 942b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 943b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 944b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 945b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 946b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 947b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 948b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 949b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 950b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 951b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 952b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 953b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 954b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 9551a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 956b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 9573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 9583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 959ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 960f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 961f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 962f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 963f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 964f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 965ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 966ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 967ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 968410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 96942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 97042c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 97161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 9722b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 9732b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 9743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 9753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 9767df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 9777df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 9787df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 97993eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim // Hotplug event is used to add/remove MHL devices as TV input. 9807df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 9813b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); 9823b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); 9837df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 9847df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 9857df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 9867df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 98793eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); 98893eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 9897df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 9903b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); 9917df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 9927df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 99393eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 99493eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 9957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 9967df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 9977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 999ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 10007df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1003a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusModeChanged(int portId, int busmode) { 10047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10053b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1007a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setBusMode(busmode); 10087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1009a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus mode change[portId:" + portId + 1010a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim ", busmode:" + busmode + "]"); 10117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1015a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusOvercurrent(int portId, boolean on) { 10167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10173b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1019a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.onBusOvercurrentDetected(on); 10207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1021a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus overcurrent event[portId:" + portId + "]"); 10227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1026a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlDeviceStatusChanged(int portId, int adopterId, int deviceId) { 10277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10283b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1029ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 10307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1031a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setDeviceStatusChange(adopterId, deviceId); 10327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1033a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for device status event[portId:" 10347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 10357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10377df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 1038ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 1039ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 1040ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 1041ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 10423b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim SparseArray<HdmiMhlLocalDeviceStub> devices = mMhlController.getAllLocalDevices(); 1043ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 10443b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = devices.valueAt(i); 1045ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 1046ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 1047ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 1048ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 1049ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1050ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 1051ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1052ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1053ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1054ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 1055ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1056ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1057ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1058ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 1059ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 1060ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1061ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1062b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private class HdmiMhlVendorCommandListenerRecord implements IBinder.DeathRecipient { 1063b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final IHdmiMhlVendorCommandListener mListener; 1064f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1065b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public HdmiMhlVendorCommandListenerRecord(IHdmiMhlVendorCommandListener listener) { 1066f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 1067f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1068f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1069f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 1070f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 1071b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.remove(this); 1072f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1073f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1074f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 107578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 107678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 107778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 107878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 107978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 108078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 108178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 108278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 108378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 108478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 108578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 108678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 108778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 108878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 108978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10903cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 10913cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 10923cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public boolean equals(Object obj) { 10933cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!(obj instanceof HotplugEventListenerRecord)) return false; 10943cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (obj == this) return true; 10953cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HotplugEventListenerRecord other = (HotplugEventListenerRecord) obj; 10963cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return other.mListener == this.mListener; 10973cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 10983cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 10993cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 11003cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public int hashCode() { 11013cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return mListener.hashCode(); 11023cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 110378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 110478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11056d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 11066d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 11076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 11096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 11106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1113ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 11146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 11156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 11166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1120ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 112138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 1122ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1123ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 1124ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 1125ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1126ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1127ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1128ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 1129ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1130ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 1131ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1132ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1133ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1134ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1135119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 1136119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 1137119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 1138119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1139119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 1140119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 1141119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 1142119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1143119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1144119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1145119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 1146119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1147119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 1148119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1149119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1150119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1151119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 115212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 1153f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 1154f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1155f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 1156f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1157f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1158f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1159b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1160b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 1161b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1162f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 1163b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1164b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1165b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1166b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 116778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 116878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 116978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 117078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 117178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 117278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 117378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 117478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 11760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 11770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 11780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 117978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 118178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 118278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 118378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 118461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 1185b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 11867e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 11877e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 11887e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 11897e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 11907e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 11917e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 11927e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 119361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 119461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 119561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 11967e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 11977e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 119861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 11997640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim HdmiDeviceInfo info = tv.getSafeDeviceInfoByPath(activePath); 1200d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId()); 12017e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12027e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 12037e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12047e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 12057e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 12068960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1207a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1208a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1209a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1210a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 121172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 121272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 121372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 121472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 121579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1216a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1217a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1218c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1219a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1220a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 12213b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId); 1222f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1223f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1224f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 122587f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 122687f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1227f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1228f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1229f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1230f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 12317c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1232f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 123387f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 12348960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1235a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1236a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1237a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1238a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1239a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1240a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1241a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1242a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1243a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1244a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 124572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 124672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 124772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 124872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1249a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1250a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1251a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1252c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1253a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1254a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 12558333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1256a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1257a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1258a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1259a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1260a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1261c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1262a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1263a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1264a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1265a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 12663b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(mActivePortId); 1267f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1268f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1269f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 12704612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 12714612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 12724612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 12734612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 12744612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 12754612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 12764612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 12774612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1278a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1279a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1280a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1281a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1282a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1283a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 12847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 128578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 12867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 12877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 12887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 12897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 12907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 12917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 129278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 129378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 129478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 12957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 129678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 12977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 12987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 12997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 13007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 13017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 130378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 130478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 130578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 130778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1308f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 130978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 131078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 131178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 131378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1314f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 131578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 13166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 13196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1320f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 13216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13246d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 13256d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 13262738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 13276d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1328ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1329ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1330ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1331ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1332ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1333ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1334ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1335ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1336e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1337ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1338ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1339ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1340ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1341ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1342ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1343ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1344ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1345ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1346377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1347ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1348ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1349ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1350ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1351ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1352ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1353ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1354ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1355ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1356ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1357ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1358c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1359ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1360ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1361ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1362ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1363ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1364ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1365ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1366ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1367ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1368ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1369ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1370ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1371ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1372ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1373ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1374ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1375ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1376ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1377ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1378ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 137992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 138092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 13819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 13829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 13839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 13849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 13869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 138761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 13889c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 13899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 13909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 13919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1392ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1393ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1394ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1395ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1396ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 13979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1400bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // Returns all the CEC devices on the bus including system audio, switch, 1401bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // even those of reserved type. 1402bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @Override 1403bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim public List<HdmiDeviceInfo> getDeviceList() { 1404bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim enforceAccessPermission(); 1405bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1406bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim synchronized (mLock) { 1407bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return (tv == null) 1408bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1409bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim : tv.getSafeCecDevicesLocked(); 1410bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1411bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1412bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 14139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 141441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 141541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 141641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 141741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 141841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 141941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 142041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 142141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 142241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 142341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 142441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 142541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 142641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 142741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 142841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 142941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 143041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 143141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 143241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 143341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 143441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 143541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 143641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 143741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 143841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 143941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 144041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 144141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 144241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 144341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 144441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 144541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 144641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1447a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1448a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1449a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1450a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1451a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1452a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1453a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 145438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1455a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1456a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1457a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1458a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1459a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1460160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1461160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 14624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 14634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 14644d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 14654d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 14664d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 14674d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 14684d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1469119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1470119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1471119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1472119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1473119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1474f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1475119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1476119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1477119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1478119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1479119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1480119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1481119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1482119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1483119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1484119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1485119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1486119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1487119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1488119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1489119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1490119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1491119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1492119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1493119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1494119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1495119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1496119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1497119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1498119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 149912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1500a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1501a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1502d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void sendStandby(final int deviceType, final int deviceId) { 1503d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim enforceAccessPermission(); 1504d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim runOnServiceThread(new Runnable() { 1505d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1506d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void run() { 150761c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim HdmiMhlLocalDeviceStub mhlDevice = mMhlController.getLocalDeviceById(deviceId); 150861c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim if (mhlDevice != null) { 150961c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mhlDevice.sendStandby(); 151061c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim return; 151161c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim } 1512d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1513d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (device == null) { 1514d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim Slog.w(TAG, "Local device not available"); 1515d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1516d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1517d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim device.sendStandby(deviceId); 1518d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1519d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim }); 1520d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1521d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 1522d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 152312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 1524b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 152512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1526b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1527b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1528b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1529b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1530b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1531b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1532b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1533b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1534de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1535de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1536b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1537b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1538b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1539b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1540b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1541b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1542b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1543b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1544b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1545b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1546b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1547b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1548b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1549de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1550de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1551b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1552b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1553b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1554b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1555b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1556a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1557a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1558a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1559b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1560b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1561b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1562b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1563b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1564b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1565de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1566de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1567b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1568b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1569b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1570b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1571b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1572bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1573bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1574bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1575b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1576b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1577b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1578b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1579b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1580b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1581de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1582de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1583b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1584b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1585b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1586b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1587b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1588a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1589f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1590f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1591b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void sendMhlVendorCommand(final int portId, final int offset, final int length, 1592f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1593f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1594f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1595f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1596f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1597f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1598f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1599f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1600f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 16013b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1602f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1603f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1604f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1605f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1606b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlController.sendVendorCommand(portId, offset, length, data); 1607f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1608f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1609f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1610f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1611f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1612b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void addHdmiMhlVendorCommandListener( 1613b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim IHdmiMhlVendorCommandListener listener) { 1614f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1615b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiControlService.this.addHdmiMhlVendorCommandListener(listener); 1616f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1617959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1618959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1619959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1620959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1621959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1622959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1623959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1624959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1625959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1626959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1627959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1628959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1629959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1630959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 163161c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 163261c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.println("mMhlController: "); 163361c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.increaseIndent(); 163461c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mMhlController.dump(pw); 163561c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.decreaseIndent(); 163661c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 1637959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1638959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1639959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1640959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1641959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1642959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1643959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1644959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 164578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 164678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1647a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 164879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 164979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 165079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 16517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 16527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1653c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 16547fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 16557fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 165679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 165778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 165878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1659a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 166079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 166179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 166279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 16637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 16647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1665c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 16667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 16677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 166879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 166978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 167078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 16713cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim private void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 16723cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 167378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 167478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 167578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 167678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 167778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 167878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 167978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 168078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 168178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 16823cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 16833cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // Inform the listener of the initial state of each HDMI port by generating 16843cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // hotplug events. 16853cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim runOnServiceThread(new Runnable() { 16863cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 16873cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public void run() { 16883cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 16893cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!mHotplugEventListenerRecords.contains(record)) return; 16903cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 16913cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim for (HdmiPortInfo port : mPortInfo) { 16923cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(port.getId(), 16933cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim mCecController.isConnected(port.getId())); 16943cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 16953cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim invokeHotplugEventListenerLocked(listener, event); 16963cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 16973cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 16983cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 16993cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim }); 170078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 170178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 170278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 170378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 170478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 170578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 170678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 170778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 170878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 170978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 17137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 17146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 17154893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 17164893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 17174893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 17184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17194893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 17204893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 17214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 17234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 17244893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17254893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 172761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 17284893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1729f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 17304893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1731f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 17324893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17334893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 17346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1739ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1740ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1741ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1742ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1743ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1744ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1745ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1746ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1747ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1748ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1749ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1750ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1751ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1752ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1753ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1754ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1755ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1756ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1757ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1758ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1759ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1760ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1761ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1762ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1763ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1764ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1765ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 17669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1767f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1768f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1769f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1770f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1771f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1772f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 17739c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 17749c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 17759c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1776f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 17779c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 17819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 17829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1783f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 17849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 17859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 17869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 17879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 17889c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 17899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 17929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 179361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 17949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1795f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 17969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1797f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 17989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 17999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 18009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 180512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1806b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1807f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1808b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 180912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1810b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 181112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1812b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1813b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1814b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1815b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1816b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1817b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1818f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 181912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1820f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 182112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 182212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1823b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1824b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1825b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1826b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1827b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1828b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1829326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeOneTouchRecordResult(int recorderAddress, int result) { 183012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1831f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 183212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1833326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(recorderAddress, result); 183412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 183512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 183612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 183712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 183812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 183912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 184012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1841326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeTimerRecordingResult(int recorderAddress, int result) { 184212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1843f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 184412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1845326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(recorderAddress, result); 184612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1847e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1848e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1849e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1850e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1851e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1852e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1853326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeClearTimerRecordingResult(int recorderAddress, int result) { 1854e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1855f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1856e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1857326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(recorderAddress, 1858326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang result); 1859e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1860e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 186112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 186212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 186312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 186412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 186512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 18667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 18677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 18687fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 18697fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 18707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 18717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 18727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 187363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1874f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1875ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1876ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1877ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1878ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1879ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1880ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1881ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1882ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 18834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 18844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 188560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1886f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1887f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 188860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 188960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 189060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 189160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 18924893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 189360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 189460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 189560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 189660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 189760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 189860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1899e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1900e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 190179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 190261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 190379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 190479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1905e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1906b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); 1907e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1908e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 1909de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim boolean isTvDeviceEnabled() { 1910de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return isTvDevice() && tv() != null; 1911de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 1912de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim 191379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1914c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 191561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 191660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1917a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1918a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1919a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1920a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 192192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 192292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 192392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 192492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 192592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 192692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 192738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1928f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 192938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1930f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 193138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 193238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 193338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1934f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 193538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1936f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1937c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1938c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 193938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 194038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1941f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 194238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1943f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1944c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1945c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 194638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 194738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1948f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 194938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1950f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1951c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 195238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 195338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 195438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 195538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 195638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1957fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 1958e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager.wakeUp(SystemClock.uptimeMillis()); 195938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 196038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 196138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 196238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 196338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 196438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 196538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 196638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 1967e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 196838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 196938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 197038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 197138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 197238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 197338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 197438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1975c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 197638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1977a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1978fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1979fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1980fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1981fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1982fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1983a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 198438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 198538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 198638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 198738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 198838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 198938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 199038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 199138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 199238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1993e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim if (!canGoToStandby()) return; 1994c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 19950608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 19960608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); 19974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 19994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 20004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 20014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 20024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 20034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 20044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 20054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 20064b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 20074b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 20084b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 20094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 20124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2014e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private boolean canGoToStandby() { 2015e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2016e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim if (!device.canGoToStandby()) return false; 2017e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2018e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return true; 2019e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2020e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 20211ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 20221ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 20231ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 20241ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 20251ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2026de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 20271ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 20285b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mCecController.setOption(OPTION_CEC_SET_LANGUAGE, HdmiUtils.languageToInt(language)); 20291ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 20301ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 20311ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2032f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 2033f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 2034f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2035f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 2036f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 2037f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 20384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 2039350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 2040350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2041350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 2042350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 204338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2044350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 2045f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 204638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 204738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 204838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 20494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 20504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 20514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 20524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 20534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 20554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 20564fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 20594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 206038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 20614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 20624fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2063c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 206438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 206538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2066c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 206738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 20684fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 206938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 207038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 2071964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = false; 20725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 20735b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED); 207438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 20754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 2076119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 2077119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 2078119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 2079119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 2080119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2081119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 2082119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 2083119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2084119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2085119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 2086119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2087119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2088119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 20890608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, 20900608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo byte[] params, boolean hasVendorId) { 2091119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2092d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (mVendorCommandListenerRecords.isEmpty()) { 2093d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return false; 2094d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 2095119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 2096119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 2097119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 2098119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2099119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 21000608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); 2101119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2102119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 2103119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2104119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2105d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return true; 2106119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2107119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2108119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 21090608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { 21100608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo synchronized (mLock) { 21110608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (mVendorCommandListenerRecords.isEmpty()) { 21120608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return false; 21130608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21140608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 21150608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo try { 21160608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onControlStateChanged(enabled, reason); 21170608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } catch (RemoteException e) { 21180608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); 21190608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21200608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21210608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return true; 21220608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21230608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21240608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 2125b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { 2126b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiMhlVendorCommandListenerRecord record = 2127b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim new HdmiMhlVendorCommandListenerRecord(listener); 2128f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2129f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 2130f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2131f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 2132f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 2133f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2134f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2135f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2136b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.add(record); 2137f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2138f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2139f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2140b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim void invokeMhlVendorCommandListeners(int portId, int offest, int length, byte[] data) { 2141f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2142b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim for (HdmiMhlVendorCommandListenerRecord record : mMhlVendorCommandListenerRecords) { 2143f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2144f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 2145f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2146b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim Slog.e(TAG, "Failed to notify MHL vendor command", e); 2147f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2148f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2149f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2150f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2151f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 21524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 21534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 21544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 21554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 21584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 21594d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 21604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 21614d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 21634fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 21644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2165350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 21665008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 21675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 21685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 21695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 21705008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 21715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 21724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 21734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 21744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 21754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 21764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 21774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 21784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 2179f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo enableHdmiControlService(); 2180f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 21814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2182f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Call the vendor handler before the service is disabled. 2183f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 2184f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 2185f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Post the remained tasks in the service thread again to give the vendor-issued-tasks 2186f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // a chance to run. 2187f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo runOnServiceThread(new Runnable() { 2188f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2189f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2190f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableHdmiControlService(); 2191f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2192f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2193f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 2194f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2195f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2196f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2197f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void enableHdmiControlService() { 2198f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 2199f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED); 2200f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2201f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 2202f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2203f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2204f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2205f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void disableHdmiControlService() { 2206f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableDevices(new PendingActionClearedCallback() { 2207f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2208f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void onCleared(HdmiCecLocalDevice device) { 2209f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo assertRunOnServiceThread(); 2210f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.flush(new Runnable() { 2211f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2212f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2213f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.setOption(OPTION_CEC_ENABLE, DISABLED); 2214f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED); 2215f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo clearLocalDevices(); 2216f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2217f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2218f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2219f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 22204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2221867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2222867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 2223867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 2224867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 2225867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 2226e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2227e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 2228e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 2229e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 2230e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2231e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2232e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2233e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 2234e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2235e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 2236e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2237e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2238e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2239e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 2240e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2241e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 2242e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2243e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2244e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 2245e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 2246e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 2247e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 2248e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 2249e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 2250e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2251e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 2252e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2253de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (tv() == null) return; 2254e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 2255cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 2256cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 2257cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim @Override 2258cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim public void onComplete(int result) throws RemoteException { 2259cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 2260cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // This effectively sets the port to invalid one if the switching is for 2261cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // RAP[ContentOff]. 2262cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim setLastInputForMhl(lastInput); 2263cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2264cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim }); 2265cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2266e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 2267e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 2268e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 2269e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2270e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 2271f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 2272e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 2273e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 22743b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 2275cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim HdmiDeviceInfo info = (device != null) ? device.getInfo() 2276cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim : mPortDeviceMap.get(portId, HdmiDeviceInfo.INACTIVE_DEVICE); 2277e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 2278867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 227908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 2280e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 2281f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 228208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 228308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 228408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 228508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 228608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 228708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 228808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 228908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 229008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 229108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 229208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 2293339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 2294339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 2295339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 2296339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2297339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2298339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2299339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2300339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2301339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 23022e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 23032e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 23042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 23052e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 23062e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 23072e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 23082b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); 23092e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 23102e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiControlService.PERMISSION); 23112e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 23120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2313