HdmiControlService.java revision 7fa3a66470d2133796defd14a0600578758882ac
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 19ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; 20ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 3138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 327ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 37c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 387d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 3960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 41d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 42d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 44d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 46b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kimimport android.hardware.hdmi.IHdmiMhlVendorCommandListener; 4712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 48ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 49119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 50a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 517fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager; 527fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager.TvInputCallback; 535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 5442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 58e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 5938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 6078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 6138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 627d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 647ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 657d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 662b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 698b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 7078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 714893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 72959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 74a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 767e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 79b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 80b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 81959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.FileDescriptor; 82959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.PrintWriter; 8378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 84f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 871ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 88a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 955fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale HONG_KONG = new Locale("zh", "HK"); 965fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale MACAU = new Locale("zh", "MO"); 970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 98c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 9978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 100fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 101fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 102fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 103fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 104fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 105b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo static final int INITIATED_BY_HOTPLUG = 4; 106fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 107d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 108d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 109d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 110d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 112d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 113d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 114ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 120d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 121d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 122d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 123d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 12402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 12602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 12802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 13002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 13102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 13202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 13402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 13502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1361ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 137f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 13838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 140f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 14238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 14438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 14538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 14738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 14938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 15038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1535fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim String language = getMenuLanguage(); 1541ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1551ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1561ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1571ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 15838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1605fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim 1615fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private String getMenuLanguage() { 1625fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim Locale locale = Locale.getDefault(); 1635fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { 1645fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Android always returns "zho" for all Chinese variants. 1655fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Use "bibliographic" code defined in CEC639-2 for traditional 1665fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Chinese used in Taiwan/Hong Kong/Macau. 1675fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return "chi"; 1685fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } else { 1695fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return locale.getISO3Language(); 1705fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 1715fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 17238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1770792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1780792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 17978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 18078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 18178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 18478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 18578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 18778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 18878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 18978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 190f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 1914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 195f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 196119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 197119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 198119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 199119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 2009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 2019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 2029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 203b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 20412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 205b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 20692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 20792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 20892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 20992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 21092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 2114d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 2124d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 2134d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2154d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2164d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 217ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 218ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 219ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 220ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 226f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 227f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 228f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2362b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 23730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2382b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2392b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 24030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2412b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 242e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 243e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 244e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 24575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 24675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 248c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 24938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 25038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2511ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2531ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 25438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 25538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 256fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 257fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 258fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 259867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 260867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 261867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 262f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 263f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 264f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 265f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 266b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim // List of records for MHL Vendor command listener to handle the caller killed in action. 267f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 268b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final ArrayList<HdmiMhlVendorCommandListenerRecord> 269b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords = new ArrayList<>(); 270f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 271f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 272f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 273f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 274f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 275781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim private HdmiMhlControllerStub mMhlController; 276f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 2777fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Nullable 2787fa3a66470d2133796defd14a0600578758882acJinsuk Kim private TvInputManager mTvInputManager; 2797fa3a66470d2133796defd14a0600578758882acJinsuk Kim 280f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 281f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 282e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 283e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 284e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 285e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2887d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2927d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2937d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2947d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2957d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2967d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2977d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2987d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2997d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 3007d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 3017d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3027d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3037d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 3047d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3057d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 3060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 3070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 3082f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 309c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 3107ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 3117ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 31208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 3138b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 314a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 3153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 316347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 3175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 318347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 319a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 320a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 321fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 322a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 323a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 3240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 32508f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim return; 3260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 328781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim mMhlController = HdmiMhlControllerStub.create(this); 329f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 3300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 3310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 332ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 333f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 334f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 33575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 3368692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 33763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 338f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 3390608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register broadcast receiver for power state change. 34038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 34138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 34238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 3431ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 3441ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 3450608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 3460608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register ContentObserver to monitor the settings change. 3470608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo registerContentObserver(); 34838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3497ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 35038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 3517fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Override 3527fa3a66470d2133796defd14a0600578758882acJinsuk Kim public void onBootPhase(int phase) { 3537fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 3547fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager = (TvInputManager) getContext().getSystemService( 3557fa3a66470d2133796defd14a0600578758882acJinsuk Kim Context.TV_INPUT_SERVICE); 3567fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 3577fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 3587fa3a66470d2133796defd14a0600578758882acJinsuk Kim 3597fa3a66470d2133796defd14a0600578758882acJinsuk Kim TvInputManager getTvInputManager() { 3607fa3a66470d2133796defd14a0600578758882acJinsuk Kim return mTvInputManager; 3617fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 3627fa3a66470d2133796defd14a0600578758882acJinsuk Kim 3637fa3a66470d2133796defd14a0600578758882acJinsuk Kim void registerTvInputCallback(TvInputCallback callback) { 3647fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 3657fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.registerCallback(callback, mHandler); 3667fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 3677fa3a66470d2133796defd14a0600578758882acJinsuk Kim 3687fa3a66470d2133796defd14a0600578758882acJinsuk Kim void unregisterTvInputCallback(TvInputCallback callback) { 3697fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 3707fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.unregisterCallback(callback); 3717fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 3727fa3a66470d2133796defd14a0600578758882acJinsuk Kim 37325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 37425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 37525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 3760608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo private void onInitializeCecComplete(int initiatedBy) { 377fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 378fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 379fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 380fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 381fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 38225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3840608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 3850608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo int reason = -1; 3860608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo switch (initiatedBy) { 3870608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_BOOT_UP: 3880608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; 3890608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3900608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_ENABLE_CEC: 3910608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; 3920608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3930608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_SCREEN_ON: 3940608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_WAKE_UP_MESSAGE: 3950608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; 3960608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3970608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 3980608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (reason != -1) { 3990608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(true, reason); 40025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 40125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 40225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 4035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 4045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 4055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 4065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 4075008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 4085008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 4095008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 4105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 4115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 4125691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 4135008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 4145008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 4155008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 4195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 4205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 4215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 423f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 4245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 4255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 4265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 4275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 4285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 4295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 4305008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 4315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4325008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 4335008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 434350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 4355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 4375008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 4385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 4395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 44108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 4425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 444f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 4455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 4515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 4525008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4547ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 4557ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 4565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 4577ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 4587ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 4597ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 4607ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 4615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 4625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 464fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 4655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 466b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo initializeLocalDevices(initiatedBy); 467a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 468a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 469a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 470b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void initializeLocalDevices(final int initiatedBy) { 471a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 472b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // A container for [Device type, Local device info]. 473b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 474b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (int type : mLocalDevices) { 4756f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 4766f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (localDevice == null) { 4776f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim localDevice = HdmiCecLocalDevice.create(this, type); 4786f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 4793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 480b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo localDevices.add(localDevice); 481b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 4826f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // It's now safe to flush existing local devices from mCecController since they were 4836f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // already moved to 'localDevices'. 4846f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim clearLocalDevices(); 485b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocateLogicalAddress(localDevices, initiatedBy); 486b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 487b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 488b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo @ServiceThreadOnly 489b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void allocateLogicalAddress(final ArrayList<HdmiCecLocalDevice> allocatingDevices, 490b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int initiatedBy) { 491b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo assertRunOnServiceThread(); 49289ec14e48f4a1bdf291cda9fba7b8172f55a2447Yuncheol Heo mCecController.clearLogicalAddress(); 493b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>(); 494b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int[] finished = new int[1]; 495b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (final HdmiCecLocalDevice localDevice : allocatingDevices) { 496b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo mCecController.allocateLogicalAddress(localDevice.getType(), 4973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 500c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 5013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 5023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 503410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 504410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 505410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 506410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 5073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 5083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 5093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 510b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocatedDevices.add(localDevice); 5113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5134893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 514b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (allocatingDevices.size() == ++finished[0]) { 515b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (initiatedBy != INITIATED_BY_HOTPLUG) { 516b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // In case of the hotplug we don't call onInitializeCecComplete() 517b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // since we reallocate the logical address only. 5180608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo onInitializeCecComplete(initiatedBy); 519b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 520b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo notifyAddressAllocated(allocatedDevices, initiatedBy); 5213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 5243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 527a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 528b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) { 529a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 530b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (HdmiCecLocalDevice device : devices) { 531b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int address = device.getDeviceInfo().getLogicalAddress(); 532fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 5333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 5370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 538a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5392b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 540a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 5420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 5440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 5450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 5460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 5470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 5492b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 5502b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5512b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 55230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 55330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 554e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 5552b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 55630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 55730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 558e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 5590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 56030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 56130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 562e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 5630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 564f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 565f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 566f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 567f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 568f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 5690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 570f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 5710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 572f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 573f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 574f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 575f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 576f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 577f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 578f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 579f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 580f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 581f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 582f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 583f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 584f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 5852b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5862b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 587f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 5880340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5890340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5902738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 5912738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 5922738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 5932738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 5940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 5950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 5960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 5970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 5980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 5990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 6000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 6012b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 6020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 604e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 605401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 606401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 607401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 608401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 609401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 610401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 611401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 612c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 613401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 614401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 615401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 616401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 617401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 618401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 619401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 620401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 621401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 622401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 623401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 624c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 6252b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 626401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 627401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 62809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 6292b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 63009ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 63109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 632401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 633e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 634e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 635e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 636e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 637e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 638e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 639e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 640e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 641e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 642e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 643e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 644e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 645e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 646e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 647e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 64867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 649e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 650c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 651c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 6523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 6533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 6543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 6553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 6563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 6593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 6603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 6613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 6623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 6633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 665a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 66661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 6670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 66879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 66979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 67079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 67179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 6728960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return tv.getCecDeviceInfo(logicalAddress); 673a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 674a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 6753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 676092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 677092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 678092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 679092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 680092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 681092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 682092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 68360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 68460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 68560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 686339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 6872b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 6882b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 68960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 69060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 69160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 69260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 69379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 69467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 69567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 69667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 69763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 69863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 69963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 70063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 70163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 70263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 70363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 70463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 70563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 70663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 70767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 708c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 709c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 710c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 711d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 712c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 713a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 714d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 715a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7164c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) { 7175f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 7185f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 7192e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.error("Invalid message type:" + command); 7205f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 7215f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 7225f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 7235f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 724d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 725d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 726a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 727d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 728a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7295f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 730c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 731c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 7326aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 7336aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 7346aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 7356aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 7366aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 7376aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 7386aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 7396aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 7406aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 7416aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 7426aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 7436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 744a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 745a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 746a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7474c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int errorCode = mMessageValidator.isValid(message); 7484c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode != HdmiCecMessageValidator.OK) { 749a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // We'll not response on the messages with the invalid source or destination 750a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // or with parameter length shorter than specified in the standard. 7514c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode == HdmiCecMessageValidator.ERROR_PARAMETER) { 7524c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); 7534c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo } 7544c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return true; 75575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 756092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 757092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 758092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 75979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 76079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 76160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 76260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 763a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 764092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 765a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 766092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 76779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 768c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 769092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 770092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 771092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 77260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 773c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 7742e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unhandled cec command:" + message); 7753a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 776092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 777a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 778a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 77967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 78067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 78167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 782ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 78367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 78467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 785a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 786ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 78760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 788b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 789b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (connected && !isTvDevice()) { 790b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 791b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo for (int type : mLocalDevices) { 792b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 793b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (localDevice == null) { 794b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice = HdmiCecLocalDevice.create(this, type); 795b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice.init(); 796b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo } 797b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevices.add(localDevice); 798b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 799b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); 800b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 801b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 80279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 803ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 80460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 805ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 80667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 80767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 80802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 80902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 81002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 81102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 81202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 8131de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 8140f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 81502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 8160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 81702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 818a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 8191de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 8201de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 821a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8221de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 8231de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 8240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 8250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 8260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 827c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 8280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 8290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 8300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 831c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 8320f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 8330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 8340f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 8350f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 83602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 83702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 83860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 83960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 84060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 84160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 84260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 84379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 84479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 84579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 84679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 84779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 848b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 849b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 850b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 851b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 852b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 853b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 854b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 855b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 856b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 857b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 858b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 859b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 860b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 8611a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 862b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 8633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 8643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 865ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 866f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 867f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 868f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 869f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 870f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 871ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 872ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 873ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 874410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 87542c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 87642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 87761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 8782b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 8792b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 8803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 8813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 8827df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8837df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 8847df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 88593eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim // Hotplug event is used to add/remove MHL devices as TV input. 8867df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 8873b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); 8883b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); 8897df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 8907df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 8917df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 8927df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 89393eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); 89493eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 8957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8963b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); 8977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 89993eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 90093eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 9017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 9027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 9037df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 905ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 9067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 9087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 909a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusModeChanged(int portId, int busmode) { 9107df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 9113b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 9127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 913a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setBusMode(busmode); 9147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 915a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus mode change[portId:" + portId + 916a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim ", busmode:" + busmode + "]"); 9177df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 9207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 921a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusOvercurrent(int portId, boolean on) { 9227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 9233b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 9247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 925a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.onBusOvercurrentDetected(on); 9267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 927a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus overcurrent event[portId:" + portId + "]"); 9287df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9297df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 9317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 932a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlDeviceStatusChanged(int portId, int adopterId, int deviceId) { 9337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 9343b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 935ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 9367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 937a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setDeviceStatusChange(adopterId, deviceId); 9387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 939a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for device status event[portId:" 9407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 9417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 944ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 945ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 946ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 947ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 9483b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim SparseArray<HdmiMhlLocalDeviceStub> devices = mMhlController.getAllLocalDevices(); 949ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 9503b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = devices.valueAt(i); 951ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 952ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 953ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 954ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 955ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 956ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 957ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 958ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 959ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 960ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 961ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 962ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 963ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 964ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 965ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 966ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 967ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 968b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private class HdmiMhlVendorCommandListenerRecord implements IBinder.DeathRecipient { 969b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final IHdmiMhlVendorCommandListener mListener; 970f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 971b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public HdmiMhlVendorCommandListenerRecord(IHdmiMhlVendorCommandListener listener) { 972f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 973f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 974f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 975f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 976f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 977b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.remove(this); 978f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 979f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 980f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 98178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 98278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 98378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 98478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 98578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 98678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 98778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 98878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 98978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 99078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 99178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 99278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 99378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 99478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 99578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 99678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 99778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 9996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 10006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 10016d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 10026d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 10036d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10046d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 10056d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1006ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 10076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 10086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 10096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 10126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1013ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 101438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 1015ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1016ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 1017ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 1018ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1019ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1020ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1021ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 1022ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1023ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 1024ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1025ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1026ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1027ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1028119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 1029119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 1030119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 1031119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1032119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 1033119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 1034119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 1035119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1036119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1037119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1038119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 1039119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1040119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 1041119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1042119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1043119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1044119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 104512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 1046f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 1047f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1048f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 1049f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1050f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1051f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1052b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1053b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 1054b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1055f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 1056b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1057b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1058b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1059b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 106078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 106178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 106278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 106378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 106478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 106578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 106678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 106778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 10690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 10700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 10710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 107278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 107478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 107578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 107678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 107761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 1078b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 10797e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 10807e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 10817e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 10827e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10837e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10847e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 10857e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 108661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 108761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 108861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 10897e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10907e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 109161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 109261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 10937e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10947e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10957e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10967e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 10977e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 10988960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1099a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1100a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1101a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1102a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 110372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 110472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 110572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 110672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 110779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1108a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1109a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1110c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1111a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1112a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 11133b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId); 1114f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1115f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1116f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 111787f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 111887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1119f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1120f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1121f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1122f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 11237c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1124f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 112587f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 11268960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1127a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1128a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1129a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1130a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1131a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1132a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1133a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1134a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1135a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1136a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 113772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 113872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 113972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 114072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1141a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1142a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1143a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1144c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1145a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1146a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 11478333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1148a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1149a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1150a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1151a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1152a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1153c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1154a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1155a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1156a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1157a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 11583b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(mActivePortId); 1159f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1160f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1161f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 11624612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 11634612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 11644612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 11654612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 11664612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 11674612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 11684612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 11694612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1170a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1171a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1172a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1173a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1174a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1175a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 11767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 117778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11817fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 11827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 118478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 118578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 118678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 118878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 11937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 119578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 119778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 119978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1200f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 120178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 120378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 12047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 120578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1206f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 120778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 12086d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 12096d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 12106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 12116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1212f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 12136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 12156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 12166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 12176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 12182738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 12196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1220ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1221ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1222ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1223ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1224ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1225ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1226ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1227ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1228e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1229ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1230ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1231ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1232ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1233ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1234ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1235ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1236ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1237ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1238377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1239ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1240ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1241ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1242ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1243ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1244ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1245ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1246ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1247ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1248ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1249ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1250c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1251ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1252ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1253ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1254ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1255ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1256ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1257ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1258ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1259ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1260ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1261ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1262ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1263ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1264ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1265ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1266ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1267ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1268ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1269ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1270ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 127192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 127292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 12739c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 12749c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12759c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 12769c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12779c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 127961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 12809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 12829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 12839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1284ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1285ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1286ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1287ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1288ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 12899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1292bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // Returns all the CEC devices on the bus including system audio, switch, 1293bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // even those of reserved type. 1294bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @Override 1295bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim public List<HdmiDeviceInfo> getDeviceList() { 1296bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim enforceAccessPermission(); 1297bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1298bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim synchronized (mLock) { 1299bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return (tv == null) 1300bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1301bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim : tv.getSafeCecDevicesLocked(); 1302bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1303bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1304bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 13059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 130641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 130741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 130841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 130941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 131041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 131141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 131241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 131341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 131441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 131541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 131641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 131741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 131841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 131941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 132041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 132141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 132241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 132341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 132441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 132541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 132641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 132741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 132841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 132941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 133041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 133141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 133241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 133341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 133441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 133541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 133641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 133741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 133841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1339a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1340a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1341a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1342a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1343a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1344a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1345a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 134638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1347a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1348a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1349a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1350a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1351a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1352160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1353160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 13544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 13554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 13564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 13574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 13584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 13594d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 13604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1361119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1362119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1363119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1364119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1365119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1366f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1367119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1368119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1369119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1370119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1371119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1372119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1373119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1374119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1375119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1376119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1377119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1378119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1379119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1380119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1381119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1382119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1383119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1384119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1385119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1386119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1387119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1388119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1389119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1390119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 139112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1392a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1393a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1394d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void sendStandby(final int deviceType, final int deviceId) { 1395d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim enforceAccessPermission(); 1396d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim runOnServiceThread(new Runnable() { 1397d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1398d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void run() { 1399d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1400d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (device == null) { 1401d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim Slog.w(TAG, "Local device not available"); 1402d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1403d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1404d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim device.sendStandby(deviceId); 1405d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1406d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim }); 1407d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1408d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 1409d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 141012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 1411b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 141212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1413b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1414b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1415b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1416b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1417b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1418b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1419b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1420b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1421b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1422b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1423b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1424b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1425b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1426b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1427b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1428b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1429b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1430b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1431b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1432b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1433b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1434b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1435b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1436b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1437b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1438b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1439b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1440b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1441b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1442b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1443a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1444a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1445a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1446b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1447b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1448b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1449b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1450b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1451b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1452b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1453b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1454b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1455b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1456b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1457b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1458b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1459bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1460bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1461bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1462b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1463b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1464b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1465b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1466b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1467b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1468b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1469b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1470b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1471b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1472b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1473b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1474b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1475a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1476f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1477f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1478b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void sendMhlVendorCommand(final int portId, final int offset, final int length, 1479f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1480f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1481f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1482f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1483f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1484f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1485f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1486f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1487f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 14883b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1489f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1490f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1491f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1492f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1493b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlController.sendVendorCommand(portId, offset, length, data); 1494f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1495f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1496f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1497f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1498f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1499b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void addHdmiMhlVendorCommandListener( 1500b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim IHdmiMhlVendorCommandListener listener) { 1501f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1502b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiControlService.this.addHdmiMhlVendorCommandListener(listener); 1503f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1504959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1505959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1506959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1507959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1508959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1509959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1510959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1511959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1512959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1513959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1514959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1515959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1516959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1517959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1518959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1519959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1520959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1521959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1522959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1523959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1524959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1525959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 152678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 152778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1528a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 152979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 153079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 153179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 15327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 15337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1534c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 15357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 15367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 153779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 153878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 153978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1540a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 154179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 154279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 154379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 15447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 15457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1546c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 15477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 15487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 154979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 155078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 155178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 155278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 155378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 155478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 155578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 155678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 155778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 155878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 155978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 156078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 156178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 156278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 156378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 156478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 156578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 156678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 156778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 156878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 156978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 157078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 157178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 157278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 157378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 157478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 157578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 15767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 15776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 15784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 15794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 15804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 15814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 15824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 15834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 15844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 15864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 15874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 159061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 15914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1592f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 15934893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1594f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 15954893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 15964893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 15976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 16006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 16016d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1602ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1603ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1604ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1605ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1606ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1607ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1608ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1609ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1610ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1611ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1612ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1613ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1614ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1615ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1616ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1617ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1618ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1619ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1620ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1621ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1622ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1623ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1624ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1625ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1626ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1627ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1628ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 16299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1630f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1631f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1632f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1633f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1634f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1635f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 16369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 16379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 16389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1639f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 16409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 16449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 16459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1646f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 16479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 16489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 16499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 16509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 16519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 16529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 165661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 16579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1658f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 16599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1660f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 16619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 16629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 16639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 166812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1669b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1670f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1671b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 167212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1673b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 167412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1675b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1676b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1677b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1678b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1679b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1680b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1681f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 168212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1683f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 168412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 168512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1686b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1687b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1688b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1689b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1690b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1691b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1692326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeOneTouchRecordResult(int recorderAddress, int result) { 169312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1694f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 169512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1696326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(recorderAddress, result); 169712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 169812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 169912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1704326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeTimerRecordingResult(int recorderAddress, int result) { 170512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1706f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 170712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1708326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(recorderAddress, result); 170912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1710e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1711e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1712e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1713e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1714e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1715e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1716326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeClearTimerRecordingResult(int recorderAddress, int result) { 1717e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1718f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1719e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1720326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(recorderAddress, 1721326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang result); 1722e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1723e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 172412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 172512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 172612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 172712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 172812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 17297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 17307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 17317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 17327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 17337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 17347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 17357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 173663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1737f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1738ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1739ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1740ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1741ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1742ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1743ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1744ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1745ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 17464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 17474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 174860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1749f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1750f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 175160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 175260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 175360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 175460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 17554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 175660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 175760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 175860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 175960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 176060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 176160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1762e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1763e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 176479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 176561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 176679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 176779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1768e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1769b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); 1770e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1771e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 177279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1773c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 177461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 177560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1776a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1777a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1778a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1779a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 178092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 178192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 178292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 178392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 178492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 178592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 178638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1787f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 178838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1789f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 179038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 179138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 179238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1793f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 179438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1795f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1796c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1797c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 179838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 179938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1800f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 180138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1802f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1803c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1804c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 180538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 180638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1807f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 180838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1809f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1810c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 181138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 181238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 181338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 181438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 181538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1816fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 181738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 181838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 181938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 182038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 182138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 182238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 182338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 182438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 182538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 182638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 182738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 1828c12035cd40d01b032013f515cb509e6c8791cf65Jeff Brown pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 182938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 183038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 183138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 183238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 183338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 183438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 183538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1836c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 183738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1838a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1839fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1840fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1841fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1842fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1843fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1844a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 184538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 184638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 184738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 184838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 184938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 185038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 185138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 185238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 185338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1854c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 18550608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 18560608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); 18574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 18594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 18604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 18614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 18624fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 18634fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 18644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 18654fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 18664b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 18674b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 18684b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 18694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 18724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18741ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 18751ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 18761ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 18771ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 18781ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 18791ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (isTvDevice()) { 18801ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 18811ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 18821ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 18831ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 1884f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 1885f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 1886f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1887f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 1888f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 1889f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 18904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 1891350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 1892350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 1893350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 1894350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 189538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1896350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 1897f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 189838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 189938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 190038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 19014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 19024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 19034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 19044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 19054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 19064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 19074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 19084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 19094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 19114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 191238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 19134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 19144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1915c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 191638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 191738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1918c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 191938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 19204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 192138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 192238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 19235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 192438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 19254d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1926119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1927119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1928119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1929119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1930119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1931119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1932119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1933119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1934119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1935119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1936119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1937119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1938119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 19390608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, 19400608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo byte[] params, boolean hasVendorId) { 1941119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1942d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (mVendorCommandListenerRecords.isEmpty()) { 1943d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return false; 1944d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1945119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1946119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1947119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1948119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1949119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 19500608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); 1951119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1952119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1953119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1954119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1955d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return true; 1956119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1957119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1958119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 19590608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { 19600608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo synchronized (mLock) { 19610608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (mVendorCommandListenerRecords.isEmpty()) { 19620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return false; 19630608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19640608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 19650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo try { 19660608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onControlStateChanged(enabled, reason); 19670608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } catch (RemoteException e) { 19680608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); 19690608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19700608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19710608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return true; 19720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19730608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19740608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 1975b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { 1976b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiMhlVendorCommandListenerRecord record = 1977b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim new HdmiMhlVendorCommandListenerRecord(listener); 1978f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1979f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 1980f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1981f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 1982f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1983f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1984f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1985f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1986b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.add(record); 1987f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1988f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1989f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1990b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim void invokeMhlVendorCommandListeners(int portId, int offest, int length, byte[] data) { 1991f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1992b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim for (HdmiMhlVendorCommandListenerRecord record : mMhlVendorCommandListenerRecords) { 1993f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1994f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 1995f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1996b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim Slog.e(TAG, "Failed to notify MHL vendor command", e); 1997f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1998f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1999f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2000f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2001f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 20024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 20034d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 20044d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 20054d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 20064d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 20074d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 20084d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 20094d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 20104d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 20114d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 20124d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 20134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2015350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 20165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 20175008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 20185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 20195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 20205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 20215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 20224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 20234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20240608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (!enabled) { 20250608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Call the vendor handler before the service is disabled. 20260608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 20270608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 20280608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 20295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 20305008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 2031f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 20324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 20344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 20354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 2038fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 20394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 20404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 20414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 20424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 20434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 20444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 20454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 20474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2049867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2050867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 2051867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 2052867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 2053867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 2054e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2055e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 2056e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 2057e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 2058e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2059e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2060e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2061e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 2062e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2063e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 2064e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2065e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2066e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2067e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 2068e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2069e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 2070e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2071e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2072e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 2073e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 2074e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 2075e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 2076e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 2077e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 2078e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2079e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 2080e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2081e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 2082e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 2083e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @Override 2084e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim public void onComplete(int result) throws RemoteException { 2085e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 2086e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // This effectively sets the port to invalid one if the switching is for 2087e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // RAP[ContentOff]. 2088e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(lastInput); 2089e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2090e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim }); 2091e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2092e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 2093e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 2094e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 2095e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2096e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 2097f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 2098e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 2099e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 21003b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 210193eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId); 2102e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 2103867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 210408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 2105e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 2106f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 210708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 210808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 210908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 211008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 211108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 211208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 211308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 211408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 211508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 211608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 211708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 2118339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 2119339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 2120339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 2121339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2122339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2123339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2124339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2125339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2126339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 21272e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 21282e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 21292e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 21302e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 21312e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 21322e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 21332b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); 21342e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 21352e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiControlService.PERMISSION); 21362e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 21370792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2138