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_MHL_ENABLE; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 265b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_SERVICE_CONTROL; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 2938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 307ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 35c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 367d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 3760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 39d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 40d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 42d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 44b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kimimport android.hardware.hdmi.IHdmiMhlVendorCommandListener; 4512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 46ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 47119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 48bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Choimport android.hardware.tv.cec.V1_0.OptionKey; 49bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Choimport android.hardware.tv.cec.V1_0.SendMessageResult; 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; 704893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 71fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkeyimport com.android.internal.util.DumpUtils; 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; 78959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.FileDescriptor; 79959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.PrintWriter; 8078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 81f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 841ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 85bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Choimport libcore.util.EmptyArray; 86a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 935fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale HONG_KONG = new Locale("zh", "HK"); 945fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private final Locale MACAU = new Locale("zh", "MO"); 950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 96c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 9778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 98fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 99fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 100fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 101fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 102fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 103b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo static final int INITIATED_BY_HOTPLUG = 4; 104fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 105e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // The reason code representing the intent action that drives the standby 106e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // procedure. The procedure starts either by Intent.ACTION_SCREEN_OFF or 107e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim // Intent.ACTION_SHUTDOWN. 108e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim static final int STANDBY_SCREEN_OFF = 0; 109e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim static final int STANDBY_SHUTDOWN = 1; 110e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 112d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 113d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 114d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 115d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 116d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 117d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 118ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 120bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho * <li>{@link SendMessageResult#SUCCESS} 121bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho * <li>{@link SendMessageResult#NACK} 122bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho * <li>{@link SendMessageResult#BUSY} 123bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho * <li>{@link SendMessageResult#FAIL} 1244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 125d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 126d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 127d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 128d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 12902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 13002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 13102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 13302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 13402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 13502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 13602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 13702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 13902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 14002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1411ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 142f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 14438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 145f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 14638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 14738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 149e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandby(STANDBY_SCREEN_OFF); 15038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 15238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 15338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 15438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 15538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1571ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1585fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim String language = getMenuLanguage(); 1591ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1601ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1611ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1621ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 163e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim case Intent.ACTION_SHUTDOWN: 164e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim if (isPowerOnOrTransient()) { 165e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandby(STANDBY_SHUTDOWN); 166e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim } 167e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim break; 16838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 16938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1705fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim 1715fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private String getMenuLanguage() { 1725fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim Locale locale = Locale.getDefault(); 1735fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { 1745fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Android always returns "zho" for all Chinese variants. 1755fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Use "bibliographic" code defined in CEC639-2 for traditional 1765fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Chinese used in Taiwan/Hong Kong/Macau. 1775fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return "chi"; 1785fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } else { 1795fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return locale.getISO3Language(); 1805fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 1815fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 18238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 18338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 18978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 19078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 19178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 19478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 19578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1964893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 19778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 19878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 19978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 200f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 2014893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 2026d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 2036d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 2046d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 205f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 206119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 207119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 208119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 209119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 2109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 2119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 2129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 213b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 21412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 215b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 21692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 21792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 21892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 21992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 22092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 2214d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 2224d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 2234d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2244d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2254d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2264d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 227ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 228ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 229ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 230ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2314893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 236f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 237f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 238f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2390792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2400792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2462b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 24730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2482b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2492b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 25030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2512b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 252e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 253e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 254e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 25575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 25675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 25738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 258c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 25938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 26038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2611ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2621ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2631ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 26438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 26538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 266fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 267fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 268fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 269867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 270867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 271867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 272f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 273f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 274f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 275f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 276b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim // List of records for MHL Vendor command listener to handle the caller killed in action. 277f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 278b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final ArrayList<HdmiMhlVendorCommandListenerRecord> 279b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords = new ArrayList<>(); 280f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 281f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 282f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 283f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 284f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 285781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim private HdmiMhlControllerStub mMhlController; 286f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 2877fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Nullable 2887fa3a66470d2133796defd14a0600578758882acJinsuk Kim private TvInputManager mTvInputManager; 2897fa3a66470d2133796defd14a0600578758882acJinsuk Kim 290e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim @Nullable 291e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private PowerManager mPowerManager; 292e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 293f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 294f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 295e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 296e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 297e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 298e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 299964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Set to true if the logical address allocation is completed. 300964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean mAddressAllocated = false; 301964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 302964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Buffer for processing the incoming cec messages while allocating logical addresses. 303964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private final class CecMessageBuffer { 304964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private List<HdmiCecMessage> mBuffer = new ArrayList<>(); 305964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 306964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void bufferMessage(HdmiCecMessage message) { 307964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim switch (message.getOpcode()) { 308964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 309964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferActiveSource(message); 310964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 311964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_IMAGE_VIEW_ON: 312964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim case Constants.MESSAGE_TEXT_VIEW_ON: 313964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim bufferImageOrTextViewOn(message); 314964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 315964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Add here if new message that needs to buffer 316964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim default: 317964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Do not need to buffer messages other than above 318964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim break; 319964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 320964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 321964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 322964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void processMessages() { 323964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (final HdmiCecMessage message : mBuffer) { 324964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim runOnServiceThread(new Runnable() { 325964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim @Override 326964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim public void run() { 327964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim handleCecCommand(message); 328964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 329964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim }); 330964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 331964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.clear(); 332964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 333964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 334964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferActiveSource(HdmiCecMessage message) { 335964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) { 336964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 337964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 338964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 339964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 340964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private void bufferImageOrTextViewOn(HdmiCecMessage message) { 341964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) && 342964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim !replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) { 343964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.add(message); 344964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 345964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 346964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 347964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim // Returns true if the message is replaced 348964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) { 349964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim for (int i = 0; i < mBuffer.size(); i++) { 350964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim HdmiCecMessage bufferedMessage = mBuffer.get(i); 351964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (bufferedMessage.getOpcode() == opcode) { 352964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mBuffer.set(i, message); 353964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 354964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 355964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 356964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return false; 357964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 358964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 359964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 360f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private final CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer(); 361f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 362f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private final SelectRequestBuffer mSelectRequestBuffer = new SelectRequestBuffer(); 363964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 3640792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 3650792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 3667d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 3675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 3680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 3707d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 3717d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 3727d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 3737d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 3747d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 3757d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 3767d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 3777d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 3787d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 3797d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3807d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3817d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 3827d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3837d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 3840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 3850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 3862f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 387c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 3887ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 3897ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 39008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 3918b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 392a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 3933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 394a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 395fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 396a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 397a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 3980792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 39908f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim return; 4000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 4010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 402781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim mMhlController = HdmiMhlControllerStub.create(this); 403f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 4040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 4050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 406ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 407f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 408f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 40975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 4108692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 41163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 412f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 4130608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register broadcast receiver for power state change. 41438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 41538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 41638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 4173059556f6092af0e292d4b3cff97ec772d2d6bd1Rob McConnell filter.addAction(Intent.ACTION_SHUTDOWN); 4181ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 4191ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 4200608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 4210608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register ContentObserver to monitor the settings change. 4220608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo registerContentObserver(); 42338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 4245b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); 4257ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 42638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 4277fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Override 4287fa3a66470d2133796defd14a0600578758882acJinsuk Kim public void onBootPhase(int phase) { 4297fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 4307fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager = (TvInputManager) getContext().getSystemService( 4317fa3a66470d2133796defd14a0600578758882acJinsuk Kim Context.TV_INPUT_SERVICE); 432e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 4337fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4347fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4357fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4367fa3a66470d2133796defd14a0600578758882acJinsuk Kim TvInputManager getTvInputManager() { 4377fa3a66470d2133796defd14a0600578758882acJinsuk Kim return mTvInputManager; 4387fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4397fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4407fa3a66470d2133796defd14a0600578758882acJinsuk Kim void registerTvInputCallback(TvInputCallback callback) { 4417fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4427fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.registerCallback(callback, mHandler); 4437fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4447fa3a66470d2133796defd14a0600578758882acJinsuk Kim 4457fa3a66470d2133796defd14a0600578758882acJinsuk Kim void unregisterTvInputCallback(TvInputCallback callback) { 4467fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (mTvInputManager == null) return; 4477fa3a66470d2133796defd14a0600578758882acJinsuk Kim mTvInputManager.unregisterCallback(callback); 4487fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4497fa3a66470d2133796defd14a0600578758882acJinsuk Kim 450e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim PowerManager getPowerManager() { 451e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return mPowerManager; 452e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 453e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 45425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 45525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 45625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 4570608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo private void onInitializeCecComplete(int initiatedBy) { 458fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 459fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 460fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 461fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 462fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 463de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 464bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setOption(OptionKey.WAKEUP, tv().getAutoWakeup()); 4650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4660608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo int reason = -1; 4670608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo switch (initiatedBy) { 4680608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_BOOT_UP: 4690608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; 4700608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4710608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_ENABLE_CEC: 4720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; 4730608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4740608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_SCREEN_ON: 4750608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_WAKE_UP_MESSAGE: 4760608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; 4770608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 4780608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 4790608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (reason != -1) { 4800608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(true, reason); 48125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 48225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 48325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 4845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 4855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 4865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 4875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 4885008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 4895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 490c1fa9afbcd1cafd205d46b2fd0bdaadccb7d29eaDonghyun Cho Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED, 4915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 4925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 4935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 4945691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 4955008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 4965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 4975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4985008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 5015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 5025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 5035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 505f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 5065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 5075008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 5085008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 5095008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 5105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 5115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 5125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 5135008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5145008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 515de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 516de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim tv().setAutoWakeup(enabled); 517de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 518bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho setCecOption(OptionKey.WAKEUP, enabled); 5195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 521e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim for (int type : mLocalDevices) { 522e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 523dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo if (localDevice != null) { 524dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo localDevice.setAutoDeviceOff(enabled); 525dd371ec1a84f06a644e8c6f5179fd8bd5f11121bTerry Heo } 526de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 5275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 5285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 529c1fa9afbcd1cafd205d46b2fd0bdaadccb7d29eaDonghyun Cho case Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED: 530c1fa9afbcd1cafd205d46b2fd0bdaadccb7d29eaDonghyun Cho if (isTvDeviceEnabled()) { 531c1fa9afbcd1cafd205d46b2fd0bdaadccb7d29eaDonghyun Cho tv().setSystemAudioControlFeatureEnabled(enabled); 5322601f8da10db7f07fcca6a7184ccfbf6c79fbec1Donghyun Cho } 5332601f8da10db7f07fcca6a7184ccfbf6c79fbec1Donghyun Cho break; 5345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 53508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 5365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5375008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 538f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 5395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 5405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 5455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 5465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 5487ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 5497ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 5517ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 5527ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 5537ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 5547ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 5555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 5565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 5575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 558fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 559964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = false; 560bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); 561bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setLanguage(mLanguage); 562b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo initializeLocalDevices(initiatedBy); 563a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 564a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 565a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 566b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void initializeLocalDevices(final int initiatedBy) { 567a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 568b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // A container for [Device type, Local device info]. 569b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 570b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (int type : mLocalDevices) { 5716f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 5726f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (localDevice == null) { 5736f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim localDevice = HdmiCecLocalDevice.create(this, type); 5746f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 5753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 576b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo localDevices.add(localDevice); 577b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 5786f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // It's now safe to flush existing local devices from mCecController since they were 5796f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // already moved to 'localDevices'. 5806f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim clearLocalDevices(); 581b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocateLogicalAddress(localDevices, initiatedBy); 582b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 583b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 584b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo @ServiceThreadOnly 585b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void allocateLogicalAddress(final ArrayList<HdmiCecLocalDevice> allocatingDevices, 586b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int initiatedBy) { 587b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo assertRunOnServiceThread(); 58889ec14e48f4a1bdf291cda9fba7b8172f55a2447Yuncheol Heo mCecController.clearLogicalAddress(); 589b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>(); 590b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int[] finished = new int[1]; 591964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = allocatingDevices.isEmpty(); 592964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim 593f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // For TV device, select request can be invoked while address allocation or device 594f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // discovery is in progress. Initialize the request here at the start of allocation, 595f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // and process the collected requests later when the allocation and device discovery 596f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim // is all completed. 597f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.clear(); 598f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 599b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (final HdmiCecLocalDevice localDevice : allocatingDevices) { 600b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo mCecController.allocateLogicalAddress(localDevice.getType(), 6013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 6023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 6033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 604c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 6053ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 6063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 607410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 608410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 609410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 610410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 6113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 6123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 6133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 614b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocatedDevices.add(localDevice); 6153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6174893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 618b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (allocatingDevices.size() == ++finished[0]) { 619964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mAddressAllocated = true; 620b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (initiatedBy != INITIATED_BY_HOTPLUG) { 621b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // In case of the hotplug we don't call onInitializeCecComplete() 622b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // since we reallocate the logical address only. 6230608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo onInitializeCecComplete(initiatedBy); 624b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 625b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo notifyAddressAllocated(allocatedDevices, initiatedBy); 626964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.processMessages(); 6273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 6303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 633a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 634b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) { 635a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 636b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (HdmiCecLocalDevice device : devices) { 637b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int address = device.getDeviceInfo().getLogicalAddress(); 638fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 6393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 640f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (isTvDeviceEnabled()) { 641f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim tv().setSelectRequestBuffer(mSelectRequestBuffer); 642f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 6433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 645fc462b962cde0a96193fc780d6466cf8b0774112Donghyun Cho boolean isAddressAllocated() { 646fc462b962cde0a96193fc780d6466cf8b0774112Donghyun Cho return mAddressAllocated; 647fc462b962cde0a96193fc780d6466cf8b0774112Donghyun Cho } 648fc462b962cde0a96193fc780d6466cf8b0774112Donghyun Cho 6490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 6500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 651a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6522b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 653a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 6550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 6560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 6570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 6580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 6590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 6600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 6610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 6622b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 6632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 66530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 66630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 667e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 6682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 66930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 67030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 671e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 6720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 67330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 67430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 675e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 6760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 677f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 678f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 679f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 680f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 681f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 6820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 683f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 6840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 685f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 686f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 687f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 688f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 689f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 690f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 691f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 692f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 693f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 694f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 695f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 696f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 697f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 6982b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 6992b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 700f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 7010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 7020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 7032738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 7042738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 7052738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 7062738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 7070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 7080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 7090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 7100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 7110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 7120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 7130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 7142b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 7150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 7160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 717e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 718401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 719401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 720401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 721401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 722401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 723401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 724401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 725c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 726401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 727401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 728401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 729401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 730401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 731401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 732401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 733401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 734401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 735401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 736401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 737c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 7382b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 739401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 740401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 74109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 7422b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 74309ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 74409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 745401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 746e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 747e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 748e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 749e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 750e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 751e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 752e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 753e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 754e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 755e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 756e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 757e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 758e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 759e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 760e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 76167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 762e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 763c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 764c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 7653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 7663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 7683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 7693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 7723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 7733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 7743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 7753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 7763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 778a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 77961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 7800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 781de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return tv() == null ? null : tv().getCecDeviceInfo(logicalAddress); 782a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 783a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 7846ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim @ServiceThreadOnly 7856ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiDeviceInfo getDeviceInfoByPort(int port) { 7866ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim assertRunOnServiceThread(); 7876ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim HdmiMhlLocalDeviceStub info = mMhlController.getLocalDevice(port); 7886ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim if (info != null) { 7896ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return info.getInfo(); 7906ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7916ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim return null; 7926ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 7936ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim 7943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 795092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 796092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 797092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 798092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 799092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 800092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 801092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 80260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 80360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 80460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 805339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 8062b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 8072b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 80860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 80960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 81060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 81160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 8127b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim @ServiceThreadOnly 8137b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim boolean isConnected(int portId) { 8147b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim assertRunOnServiceThread(); 8157b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim return mCecController.isConnected(portId); 8167b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim } 8177b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim 81879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 81967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 82067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 82167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 82263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 82363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 82463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 82563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 82663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 82763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 82863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 82963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 83063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 83163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 83267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 833c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 834c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 835c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 836d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 837c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 838a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 839d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 840a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8414c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) { 8425f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 8435f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 8442e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.error("Invalid message type:" + command); 8455f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 846bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho callback.onSendCompleted(SendMessageResult.FAIL); 8475f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 8485f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 849d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 850d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 851a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 852d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 853a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 8545f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 855c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 856c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 8576aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 8586aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 8596aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 8606aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 8616aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 8626aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 8636aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 8646aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 8656aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 8666aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 8676aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 8686aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 869a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 870a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 871a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 872964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim if (!mAddressAllocated) { 873964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim mCecMessageBuffer.bufferMessage(message); 874964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim return true; 875964c00dd7b270dcf80aea3450bbfc23502965cceJinsuk Kim } 8764c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int errorCode = mMessageValidator.isValid(message); 8774c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode != HdmiCecMessageValidator.OK) { 878a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // We'll not response on the messages with the invalid source or destination 879a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // or with parameter length shorter than specified in the standard. 8804c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode == HdmiCecMessageValidator.ERROR_PARAMETER) { 8814c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); 8824c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo } 8834c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return true; 88475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 885092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 886092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 887092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 888bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho void enableAudioReturnChannel(int portId, boolean enabled) { 889bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.enableAudioReturnChannel(portId, enabled); 89060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 89160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 892a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 893092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 894a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 895092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 89679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 897c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 898092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 899092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 900092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 90160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 902c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 9032e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unhandled cec command:" + message); 9043a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 905092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 906a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 907a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 90867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 90967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 91067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 911ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 91267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 91367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 914a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 915ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 91660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 917b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 918b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (connected && !isTvDevice()) { 919b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 920b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo for (int type : mLocalDevices) { 921b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 922b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (localDevice == null) { 923b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice = HdmiCecLocalDevice.create(this, type); 924b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice.init(); 925b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo } 926b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevices.add(localDevice); 927b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 928b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); 929b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 930b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 93179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 932ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 93360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 934ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 93567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 93667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 93702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 93802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 93902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 94002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 94102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 9421de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 9430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 94402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 9450f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 94602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 947a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 9481de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 9491de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 950a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 9511de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 9521de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 9530f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9540f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 9550f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 956c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 9570f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 9580f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 9590f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 960c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 9610f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 9620f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 9630f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 9640f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 96502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 96602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 96760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 96860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 96960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 97060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 97160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 97279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 97379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 97479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 97579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 97679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 9776561845b560bdedfcc1ba6edfbdecd6122c02e00Donghyun Cho if (!isTvDeviceEnabled() || !tv().isSystemAudioActivated()) { 9786561845b560bdedfcc1ba6edfbdecd6122c02e00Donghyun Cho return; 9796561845b560bdedfcc1ba6edfbdecd6122c02e00Donghyun Cho } 980b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 981b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 982b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 983b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 984b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 985b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 986b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 987b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 988b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 989b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 990b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 991b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 992b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 9931a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 994b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 9953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 9963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 997ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 998f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 999f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 1000f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 1001f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 1002f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1003ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1004ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1005ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1006410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 100742c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 100842c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 100961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 10102b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 10112b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 10123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 10133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 10147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 10157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 10167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 101793eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim // Hotplug event is used to add/remove MHL devices as TV input. 10187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 10193b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); 10203b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); 10217df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 10227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 10237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 10247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 102593eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); 102693eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 10277df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 10283b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); 10297df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 10307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 103193eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 103293eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 10337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 10347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 10357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 1037ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 10387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1041a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusModeChanged(int portId, int busmode) { 10427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10433b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10447df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1045a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setBusMode(busmode); 10467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1047a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus mode change[portId:" + portId + 1048a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim ", busmode:" + busmode + "]"); 10497df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10517df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10527df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1053a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusOvercurrent(int portId, boolean on) { 10547df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10553b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 10567df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1057a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.onBusOvercurrentDetected(on); 10587df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1059a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus overcurrent event[portId:" + portId + "]"); 10607df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10617df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10627df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 10637df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 1064a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlDeviceStatusChanged(int portId, int adopterId, int deviceId) { 10657df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 10663b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1067ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 10687df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 1069a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setDeviceStatusChange(adopterId, deviceId); 10707df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 1071a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for device status event[portId:" 10727df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 10737df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10747df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 10757df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 1076ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 1077ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 1078ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 1079ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 10803b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim SparseArray<HdmiMhlLocalDeviceStub> devices = mMhlController.getAllLocalDevices(); 1081ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 10823b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = devices.valueAt(i); 1083ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 1084ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 1085ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 1086ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 1087ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1088ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 1089ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1090ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1091ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1092ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 1093ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1094ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1095ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1096ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 1097ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 1098ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 1099ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 1100b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private class HdmiMhlVendorCommandListenerRecord implements IBinder.DeathRecipient { 1101b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final IHdmiMhlVendorCommandListener mListener; 1102f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1103b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public HdmiMhlVendorCommandListenerRecord(IHdmiMhlVendorCommandListener listener) { 1104f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 1105f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1106f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 1107f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 1108f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 1109b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.remove(this); 1110f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1111f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 1112f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 111378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 111478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 111578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 111678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 111778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 111878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 111978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 112078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 112178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 112278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 112378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 112478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 112578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 112678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 112778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11283cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 11293cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 11303cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public boolean equals(Object obj) { 11313cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!(obj instanceof HotplugEventListenerRecord)) return false; 11323cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (obj == this) return true; 11333cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HotplugEventListenerRecord other = (HotplugEventListenerRecord) obj; 11343cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return other.mListener == this.mListener; 11353cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 11363cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 11373cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 11383cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public int hashCode() { 11393cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim return mListener.hashCode(); 11403cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 114178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 114278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 11436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 11446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 11456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11466d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 11476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 11486d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11496d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 1151ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 11526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 11536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 11546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11566d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1158ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 115938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 1160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 1162ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 1163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1165ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1166ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 1167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1168ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 1169ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1170ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1172ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1173119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 1174119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 1175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 1176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1177119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 1178119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 1179119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 1180119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1181119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1182119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1183119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 1184119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1185119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 1186119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1187119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1188119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1189119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 119012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 1191f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 1192f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1193f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 1194f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1195f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1196f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1197b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1198b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 1199b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1200fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho if (mRecordListenerRecord == this) { 1201fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho mRecordListenerRecord = null; 1202fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho } 1203b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1204b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1205b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1206b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 120778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 120878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 120978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 121078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 121178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 121278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 121378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 121478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 12150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 12160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 12170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 12180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 121978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 12200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 122178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 122278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 122378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 122461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 1225b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 12267e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 12277e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 12287e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 12297e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 12307e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12317e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 12327e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 123361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 123461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 123561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 12367e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12377e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 123861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 12397640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim HdmiDeviceInfo info = tv.getSafeDeviceInfoByPath(activePath); 1240d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return (info != null) ? info : new HdmiDeviceInfo(activePath, tv.getActivePortId()); 12417e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12427e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 12437e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 12447e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 12457e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 12468960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1247a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1248a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1249a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1250a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 125172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 125272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 125372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 125472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 125579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1256a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1257f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (!mAddressAllocated) { 1258f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.set(SelectRequestBuffer.newDeviceSelect( 1259f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim HdmiControlService.this, deviceId, callback)); 1260f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim return; 1261f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 1262a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1263c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1264a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1265a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 12663b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId); 1267f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1268f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1269f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 127087f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 127187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1272f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1273f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1274f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1275f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 12767c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1277f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 127887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 12798960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1280a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1281a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1282a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1283a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1284a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1285a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1286a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1287a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1288a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1289a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 129072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 129172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 129272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 129372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1294a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1295a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1296f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim if (!mAddressAllocated) { 1297f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.set(SelectRequestBuffer.newPortSelect( 1298f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim HdmiControlService.this, portId, callback)); 1299f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim return; 1300f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 1301a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1302c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1303a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1304a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 13058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1306a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1307a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1308a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1309a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1310a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1311c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1312a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1313a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1314a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1315a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 13163b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(mActivePortId); 1317f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1318f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1319f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 13204612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 13214612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 13224612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 13234612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 13244612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 13254612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 13264612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 13274612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1328a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1329a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1330a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1331a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1332a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1333a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 13347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 133578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 13367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 13377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 13387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 13397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 13407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 134278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 134378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 134478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 134678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 13477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 13487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 13497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 13507fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 13517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 135378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 135478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 135578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 135778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1358f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 135978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 136078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 136178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 13627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 136378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1364f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 136578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 13666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 13696d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1370f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 13716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 13726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 13736d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 13746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 13756d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 13762738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 13776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1378ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1379ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1380ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1381ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1382ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1383ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1384ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1385ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1386e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1387ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1388ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1389ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1390ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1391ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1392ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1393ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1394ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1395ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1396377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1397ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1398ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1399ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1400ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1401ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1402ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1403ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1404ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1405ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1406ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1407ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1408c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1409ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1410ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1411ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1412ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1413ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1414ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1415ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1416ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1417ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1418ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1419ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1420ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1421ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1422ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1423ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1424ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1425ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1426ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1427ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1428ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 142992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 143092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 14319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 14329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 14339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 14349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 14369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 143761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 14389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 14399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 14409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 14419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1442ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1443ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1444ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1445ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1446ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 14479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 14499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1450bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // Returns all the CEC devices on the bus including system audio, switch, 1451bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // even those of reserved type. 1452bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @Override 1453bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim public List<HdmiDeviceInfo> getDeviceList() { 1454bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim enforceAccessPermission(); 1455bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1456bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim synchronized (mLock) { 1457bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return (tv == null) 1458bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1459bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim : tv.getSafeCecDevicesLocked(); 1460bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1461bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1462bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 14639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 146441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 146541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 146641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 146741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 146841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 146941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 147041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 147141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 147241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 147341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 147441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 147541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 147641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 147741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 147841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 147941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 148041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 148141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 148241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 148341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 148441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 148541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 148641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 148741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 148841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 148941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 149041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 149141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 149241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 149341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 149441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 149541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 149641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1497a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1498a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1499a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1500a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1501a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1502a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1503a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 150438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1505a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1506a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1507a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1508a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1509a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1510160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1511160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 15124d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 15134d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 15144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 15154d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 15164d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15174d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 15184d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1519119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1520119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1521119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1522119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1523119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1524f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1525119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1526119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1527119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1528119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1529119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1530119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1531119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1532119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1533119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1534119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1535119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1536119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1537119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1538119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1539119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1540119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1541119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1542119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1543119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1544119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1545119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1546119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1547119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1548119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 154912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1550a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1551a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1552d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void sendStandby(final int deviceType, final int deviceId) { 1553d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim enforceAccessPermission(); 1554d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim runOnServiceThread(new Runnable() { 1555d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1556d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void run() { 155761c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim HdmiMhlLocalDeviceStub mhlDevice = mMhlController.getLocalDeviceById(deviceId); 155861c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim if (mhlDevice != null) { 155961c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mhlDevice.sendStandby(); 156061c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim return; 156161c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim } 1562d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1563d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (device == null) { 1564d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim Slog.w(TAG, "Local device not available"); 1565d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1566d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1567d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim device.sendStandby(deviceId); 1568d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1569d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim }); 1570d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1571d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 1572d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 157312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 1574b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 157512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1576b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1577b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1578b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1579b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1580b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1581b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1582b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1583b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1584de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1585de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1586b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1587b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1588b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1589b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1590b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1591b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1592b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1593b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1594b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1595b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1596b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1597b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1598b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1599de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1600de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1601b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1602b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1603b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1604b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1605b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1606a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1607a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1608a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1609b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1610b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1611b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1612b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1613b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1614b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1615de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1616de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1617b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1618b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1619b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1620b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1621b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1622bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1623bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1624bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1625b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1626b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1627b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1628b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1629b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1630b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1631de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (!isTvDeviceEnabled()) { 1632de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim Slog.w(TAG, "TV device is not enabled."); 1633b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1634b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1635b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1636b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1637b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1638a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1639f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1640f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1641b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void sendMhlVendorCommand(final int portId, final int offset, final int length, 1642f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1643f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1644f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1645f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1646f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1647f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1648f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1649f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1650f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 16513b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1652f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1653f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1654f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1655f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1656b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlController.sendVendorCommand(portId, offset, length, data); 1657f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1658f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1659f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1660f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1661f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1662b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void addHdmiMhlVendorCommandListener( 1663b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim IHdmiMhlVendorCommandListener listener) { 1664f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1665b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiControlService.this.addHdmiMhlVendorCommandListener(listener); 1666f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1667959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1668959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1669b3515648fb76a04a218666f166e0a26549343178Donghyun Cho public void setStandbyMode(final boolean isStandbyModeOn) { 1670b3515648fb76a04a218666f166e0a26549343178Donghyun Cho enforceAccessPermission(); 1671b3515648fb76a04a218666f166e0a26549343178Donghyun Cho runOnServiceThread(new Runnable() { 1672b3515648fb76a04a218666f166e0a26549343178Donghyun Cho @Override 1673b3515648fb76a04a218666f166e0a26549343178Donghyun Cho public void run() { 1674b3515648fb76a04a218666f166e0a26549343178Donghyun Cho HdmiControlService.this.setStandbyMode(isStandbyModeOn); 1675b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 1676b3515648fb76a04a218666f166e0a26549343178Donghyun Cho }); 1677b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 1678b3515648fb76a04a218666f166e0a26549343178Donghyun Cho 1679b3515648fb76a04a218666f166e0a26549343178Donghyun Cho @Override 1680959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1681fe9a53bc45fd0124a876dc0a49680aaf86641d3eJeff Sharkey if (!DumpUtils.checkDumpPermission(getContext(), TAG, writer)) return; 1682959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1683959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1684959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1685959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1686959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1687959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1688959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1689959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1690959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1691959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 169261c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 169361c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.println("mMhlController: "); 169461c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.increaseIndent(); 169561c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim mMhlController.dump(pw); 169661c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim pw.decreaseIndent(); 169761c94d1a03971b07c4ac28af678f3fff6b695c32Jinsuk Kim 1698959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1699959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1700959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1701959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1702959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1703959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1704959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1705959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 170678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 170778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1708a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 170979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 171079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 171179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 17127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 17137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1714c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 17157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 17167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 171779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 171878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 171978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1720a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 172179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 172279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 172379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 17247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 17257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1726c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 17277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 17287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 172979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 173078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 173178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 17323cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim private void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 17333cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim final HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 173478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 173578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 173678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 173778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 173878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 173978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 174078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 174178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 174278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 17433cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim 17443cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // Inform the listener of the initial state of each HDMI port by generating 17453cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim // hotplug events. 17463cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim runOnServiceThread(new Runnable() { 17473cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim @Override 17483cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim public void run() { 17493cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 17503cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim if (!mHotplugEventListenerRecords.contains(record)) return; 17513cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17523cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim for (HdmiPortInfo port : mPortInfo) { 17533cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(port.getId(), 17543cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim mCecController.isConnected(port.getId())); 17553cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim synchronized (mLock) { 17563cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim invokeHotplugEventListenerLocked(listener, event); 17573cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17583cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17593cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim } 17603cd30516ad16150dee55ad8f704a0c3bf20b58b2Jinsuk Kim }); 176178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 176278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 176378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 176478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 176578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 176678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 176778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 176878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 176978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 177078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 177178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 177278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 177378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 17747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 17756d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 17764893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 17774893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 17784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 17794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 17814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 17824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 17844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 17854893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 17874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 178861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 17894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1790f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 17914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1792f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 17934893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 17944893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 17956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 17996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1800ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1801ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1802ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1803ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1804ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1805ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1806ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1807ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1808ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1809ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1810ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1811ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1812ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1813ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1814ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1815ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1816ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1817ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1818ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1819ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1820ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1821ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1822ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1823ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1824ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1825ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1826ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 18279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1828f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1829f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1830f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1831f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1832f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1833f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 18349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 18359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 18369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1837fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho if (mInputChangeListenerRecord == this) { 1838fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho mInputChangeListenerRecord = null; 1839fbbeb3e54a73e0fa7dbd5c2c1093705e69ae27daDonghyun Cho } 18409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 18449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 18459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1846f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 18479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 18489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 18499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 18509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 18519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 18529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 185661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 18579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1858f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 18599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1860f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 18619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 18629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 18639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 18679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 186812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1869b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1870f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1871b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 187212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1873b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 187412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1875b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1876b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1877b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1878b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1879b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1880b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1881f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 188212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1883f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 188412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 188512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1886b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1887b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1888b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1889b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1890b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1891b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1892326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeOneTouchRecordResult(int recorderAddress, int result) { 189312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1894f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 189512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1896326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(recorderAddress, result); 189712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 189812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 189912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 190312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1904326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeTimerRecordingResult(int recorderAddress, int result) { 190512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1906f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 190712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1908326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(recorderAddress, result); 190912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1910e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1911e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1912e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1913e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1914e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1915e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1916326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeClearTimerRecordingResult(int recorderAddress, int result) { 1917e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1918f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1919e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1920326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(recorderAddress, 1921326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang result); 1922e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1923e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 192412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 192512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 192612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 192712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 192812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 19297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 19307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 19317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 19327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 19337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 19347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 19357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 193663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1937f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1938ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1939ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1940ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1941ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1942ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1943ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1944ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1945ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 19464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 19474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 194860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1949f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1950f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 195160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 195260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 195360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 195460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 19554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 195660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 195760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 195860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 195960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 196060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 196160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1962e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1963e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 1964f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim public HdmiCecLocalDeviceTv tv() { 196561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 196679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 196779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1968e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1969b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); 1970e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1971e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 1972de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim boolean isTvDeviceEnabled() { 1973de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim return isTvDevice() && tv() != null; 1974de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim } 1975de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim 197679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1977c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 197861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 197960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1980a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1981a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1982a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1983a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 198492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 198592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 198692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 198792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 198892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 198992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 199038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1991f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 199238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1993f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 199438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 199538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 199638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1997f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 199838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1999f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2000c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 2001c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 200238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 200338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 2004f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 200538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 2006f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2007c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 2008c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 200938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 201038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 2011f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 201238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 2013f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2014c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 201538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 201638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 201738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 201838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 201938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 2020fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 2021280a64e793d081847c5dcea23ed9be38aa5332d2Dianne Hackborn mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE"); 202238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 202338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 202438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 202538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 202638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 202738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 202838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 202902920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho if (!canGoToStandby()) { 203002920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho return; 203102920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho } 203238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 2033e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim mPowerManager.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 203438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 203538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 203638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 203738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 2038afd26a250777521f692cbc2553349210f69a1bc1Donghyun Cho boolean isWakeUpMessageReceived() { 2039afd26a250777521f692cbc2553349210f69a1bc1Donghyun Cho return mWakeUpMessageReceived; 2040afd26a250777521f692cbc2553349210f69a1bc1Donghyun Cho } 2041afd26a250777521f692cbc2553349210f69a1bc1Donghyun Cho 204238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 204338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 204438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 2045c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 204638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 2047a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 2048fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 2049fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 2050fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 2051fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 2052fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 2053a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 205438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 205538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 205638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 205738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 205838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 205938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 206038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2061e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim private void onStandby(final int standbyAction) { 206238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 2063c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 20640608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 20650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); 206602920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho if (!canGoToStandby()) { 206702920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 206802920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho return; 206902920a08e129eb58b6c2e35ccda6183ab6503a98Donghyun Cho } 20704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 20724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 20734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 20744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 20754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 20764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 20774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 2078e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim onStandbyCompleted(standbyAction); 20794b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 20804b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 20814b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 20824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 20854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2087e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim private boolean canGoToStandby() { 2088e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2089e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim if (!device.canGoToStandby()) return false; 2090e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2091e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return true; 2092e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 2093e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 20941ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 20951ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 20961ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 20971ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 20981ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2099de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (isTvDeviceEnabled()) { 21001ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 2101bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setLanguage(language); 21021ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 21031ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 21041ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2105f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 2106f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 2107f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 2108f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 2109f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 2110f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 21114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 2112350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 2113350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2114350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 2115350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 211638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2117350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 2118f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 211938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 212038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 212138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 21224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 21234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 21244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 21254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 21264fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 21274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 21284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 21294fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 21304fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 21314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2132e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim private void onStandbyCompleted(int standbyAction) { 213338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 21344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 21354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 2136c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 213738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 213838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2139c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 214038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 2141e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim device.onStandby(mStandbyMessageReceived, standbyAction); 214238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 214338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 2144bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, false); 21455b8cb00b8a302329b98a5528eaa7934d0f5c3e65Jinsuk Kim mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, DISABLED); 214638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 21474d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 2148119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 2149119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 2150119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 2151119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 2152119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2153119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 2154119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 2155119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2156119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2157119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 2158119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2159119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2160119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 21610608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, 21620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo byte[] params, boolean hasVendorId) { 2163119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 2164d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (mVendorCommandListenerRecords.isEmpty()) { 2165d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return false; 2166d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 2167119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 2168119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 2169119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 2170119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2171119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 21720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); 2173119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 2174119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 2175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2177d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return true; 2178119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2179119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 2180119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 21810608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { 21820608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo synchronized (mLock) { 21830608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (mVendorCommandListenerRecords.isEmpty()) { 21840608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return false; 21850608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21860608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 21870608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo try { 21880608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onControlStateChanged(enabled, reason); 21890608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } catch (RemoteException e) { 21900608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); 21910608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21920608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21930608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return true; 21940608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21950608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 21960608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 2197b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { 2198b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiMhlVendorCommandListenerRecord record = 2199b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim new HdmiMhlVendorCommandListenerRecord(listener); 2200f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2201f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 2202f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2203f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 2204f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 2205f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2206f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2207f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2208b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.add(record); 2209f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2210f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2211f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2212b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim void invokeMhlVendorCommandListeners(int portId, int offest, int length, byte[] data) { 2213f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 2214b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim for (HdmiMhlVendorCommandListenerRecord record : mMhlVendorCommandListenerRecords) { 2215f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 2216f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 2217f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 2218b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim Slog.e(TAG, "Failed to notify MHL vendor command", e); 2219f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2220f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2221f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2222f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 2223f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2224b3515648fb76a04a218666f166e0a26549343178Donghyun Cho void setStandbyMode(boolean isStandbyModeOn) { 2225b3515648fb76a04a218666f166e0a26549343178Donghyun Cho assertRunOnServiceThread(); 2226b3515648fb76a04a218666f166e0a26549343178Donghyun Cho if (isPowerOnOrTransient() && isStandbyModeOn) { 2227b3515648fb76a04a218666f166e0a26549343178Donghyun Cho mPowerManager.goToSleep(SystemClock.uptimeMillis(), 2228b3515648fb76a04a218666f166e0a26549343178Donghyun Cho PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 2229b3515648fb76a04a218666f166e0a26549343178Donghyun Cho if (playback() != null) { 2230b3515648fb76a04a218666f166e0a26549343178Donghyun Cho playback().sendStandby(0 /* unused */); 2231b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2232b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } else if (isPowerStandbyOrTransient() && !isStandbyModeOn) { 2233b3515648fb76a04a218666f166e0a26549343178Donghyun Cho mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE"); 2234b3515648fb76a04a218666f166e0a26549343178Donghyun Cho if (playback() != null) { 2235b3515648fb76a04a218666f166e0a26549343178Donghyun Cho oneTouchPlay(new IHdmiControlCallback.Stub() { 2236b3515648fb76a04a218666f166e0a26549343178Donghyun Cho @Override 2237b3515648fb76a04a218666f166e0a26549343178Donghyun Cho public void onComplete(int result) { 2238b3515648fb76a04a218666f166e0a26549343178Donghyun Cho if (result != HdmiControlManager.RESULT_SUCCESS) { 2239b3515648fb76a04a218666f166e0a26549343178Donghyun Cho Slog.w(TAG, "Failed to complete 'one touch play'. result=" + result); 2240b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2241b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2242b3515648fb76a04a218666f166e0a26549343178Donghyun Cho }); 2243b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2244b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2245b3515648fb76a04a218666f166e0a26549343178Donghyun Cho } 2246b3515648fb76a04a218666f166e0a26549343178Donghyun Cho 22474d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 22484d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 22494d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 22504d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22514d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 22534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 22544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 22554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 22564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 22584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 2260bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho void setCecOption(int key, boolean value) { 22615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 22625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 22635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 22645008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 22655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 22665008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 22674fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 22684fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 22704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 22714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 22724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 22734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 2274f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo enableHdmiControlService(); 2275f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 22764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2277f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Call the vendor handler before the service is disabled. 2278f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 2279f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 2280f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // Post the remained tasks in the service thread again to give the vendor-issued-tasks 2281f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo // a chance to run. 2282f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo runOnServiceThread(new Runnable() { 2283f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2284f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2285f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableHdmiControlService(); 2286f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2287f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2288f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo return; 2289f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2290f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2291f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2292f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void enableHdmiControlService() { 2293bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setOption(OptionKey.SYSTEM_CEC_CONTROL, true); 2294f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, ENABLED); 2295f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2296f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 2297f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2298f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo 2299f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @ServiceThreadOnly 2300f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo private void disableHdmiControlService() { 2301f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo disableDevices(new PendingActionClearedCallback() { 2302f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2303f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void onCleared(HdmiCecLocalDevice device) { 2304f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo assertRunOnServiceThread(); 2305f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mCecController.flush(new Runnable() { 2306f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo @Override 2307f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo public void run() { 2308bc6e372b25d7d62efecefba09304c5a66218c91aDonghyun Cho mCecController.setOption(OptionKey.ENABLE_CEC, false); 2309f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo mMhlController.setOption(OPTION_MHL_ENABLE, DISABLED); 2310f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo clearLocalDevices(); 2311f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2312f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 2313f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo } 2314f17024873b10dabed069e502030dd85d6257c0c4Yuncheol Heo }); 23154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2316867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2317867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 2318867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 2319867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 2320867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 2321e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2322e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 2323e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 2324e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 2325e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2326e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2327e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2328e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 2329e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2330e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 2331e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2332e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2333e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2334e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 2335e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2336e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 2337e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2338e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2339e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 2340e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 2341e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 2342e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 2343e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 2344e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 2345e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2346e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 2347e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2348de7a4248d8631099544e4cf43c02b10131cf6672Jinsuk Kim if (tv() == null) return; 2349e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 2350cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 2351cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 2352cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim @Override 2353cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim public void onComplete(int result) throws RemoteException { 2354cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 2355cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // This effectively sets the port to invalid one if the switching is for 2356cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // RAP[ContentOff]. 2357cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim setLastInputForMhl(lastInput); 2358cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2359cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim }); 2360cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } 2361e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 2362e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 2363e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 2364e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2365e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 2366f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 2367e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 2368e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 23693b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 2370cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim HdmiDeviceInfo info = (device != null) ? device.getInfo() 2371cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim : mPortDeviceMap.get(portId, HdmiDeviceInfo.INACTIVE_DEVICE); 2372e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 2373867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 237408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 2375e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 2376f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 237708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 237808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 237908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 238008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 238108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 238208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 238308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 238408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 238508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 238608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 238708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 2388339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 2389339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 2390339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 2391339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2392339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2393339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2394339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2395339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2396339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 23972e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 23982e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 23992e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 24002e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 24012e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 24022e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 24032b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); 24042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 24052e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiControlService.PERMISSION); 24062e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 24070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2408