HdmiControlService.java revision a95f1a9b89ba321f39fd9926388d157f831db9b2
10792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/* 20792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Copyright (C) 2014 The Android Open Source Project 30792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 40792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Licensed under the Apache License, Version 2.0 (the "License"); 50792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * you may not use this file except in compliance with the License. 60792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * You may obtain a copy of the License at 70792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 80792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * http://www.apache.org/licenses/LICENSE-2.0 90792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * 100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Unless required by applicable law or agreed to in writing, software 110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * distributed under the License is distributed on an "AS IS" BASIS, 120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * See the License for the specific language governing permissions and 140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * limitations under the License. 150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 170792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpackage com.android.server.hdmi; 180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 19ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_ADD_DEVICE; 20ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kimimport static android.hardware.hdmi.HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE; 215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.DISABLED; 225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.ENABLED; 235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_AUTO_WAKEUP; 245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_ENABLE; 255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_CEC_SERVICE_CONTROL; 265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_ENABLE; 275008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_INPUT_SWITCHING; 285008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport static com.android.server.hdmi.Constants.OPTION_MHL_POWER_CHARGE; 295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 3138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 327ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 3438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 3538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.database.ContentObserver; 37c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 387d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.hardware.hdmi.HdmiDeviceInfo; 3960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 41d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 42d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 44d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 46b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kimimport android.hardware.hdmi.IHdmiMhlVendorCommandListener; 4712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 48ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 49119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 50a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.net.Uri; 5242c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 5367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 5578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 56e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 5738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 5878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 5938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 607d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.os.SystemProperties; 615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.os.UserHandle; 627ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 637d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heoimport android.text.TextUtils; 642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 650792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 678b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 6878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 694893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 70959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 710792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 72a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 747e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 77b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 78b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 79959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.FileDescriptor; 80959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport java.io.PrintWriter; 8178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 82f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 851ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 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 105d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 106d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 107d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 108d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 109d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 110d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 111d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 112ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 118d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 119d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 120d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 121d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 12202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 12402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 12602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 12802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 12902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 13002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 13102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 13202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 13302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1341ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 135f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 13638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 13738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 138f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 14238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 14538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 14638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 14738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1501ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1515fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim String language = getMenuLanguage(); 1521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1531ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1541ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1551ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 15638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1585fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim 1595fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim private String getMenuLanguage() { 1605fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim Locale locale = Locale.getDefault(); 1615fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim if (locale.equals(Locale.TAIWAN) || locale.equals(HONG_KONG) || locale.equals(MACAU)) { 1625fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Android always returns "zho" for all Chinese variants. 1635fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Use "bibliographic" code defined in CEC639-2 for traditional 1645fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim // Chinese used in Taiwan/Hong Kong/Macau. 1655fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return "chi"; 1665fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } else { 1675fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim return locale.getISO3Language(); 1685fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 1695fe3a6cbfc50a8faf9cf051f1f09a7eb1ef6b7eeJinsuk Kim } 17038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 17778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 17878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 17978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1810340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 18278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 18378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 18578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 18678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 18778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 188f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 1894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 193f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 194119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 195119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 196119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 197119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 2009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 201b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 20212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 203b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 20492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 20592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 20692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 20792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 20892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 2094d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 2104d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 2114d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 2124d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2134d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 215ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 216ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 217ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 218ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2194893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 224f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 225f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 226f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2270792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2342b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 23530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2362b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2372b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 23830c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2392b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 240e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 241e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 242e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 24375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 24475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 246c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 24738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 24838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2491ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2501ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2511ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 25238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 25338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 254fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 255fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 256fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 257867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 258867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 259867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 260f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 261f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 262f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 263f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 264b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim // List of records for MHL Vendor command listener to handle the caller killed in action. 265f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 266b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final ArrayList<HdmiMhlVendorCommandListenerRecord> 267b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords = new ArrayList<>(); 268f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 269f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 270f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 271f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 272f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 273781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim private HdmiMhlControllerStub mMhlController; 274f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 275f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 276f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 277e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 278e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 279e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 280e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2837d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2877d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2887d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2897d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2907d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2917d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2927d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2937d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2947d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 2957d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 2967d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2977d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2987d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 2997d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 3007d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 3010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 3020792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 3032f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 304c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 3057ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 3067ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 30708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 3088b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 309a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 3103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 311347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 3125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 313347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 314a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 315a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 316fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 317a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 318a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 3190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 32008f1ab02d6de42756825a2dfa7027137ff959bd8Jinsuk Kim return; 3210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 323781041239f2931ca16c902fb371cd041b057c918Jinsuk Kim mMhlController = HdmiMhlControllerStub.create(this); 324f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 3250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 3260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 327ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 328f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 329f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 33075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 3318692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 33263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 333f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 3340608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register broadcast receiver for power state change. 33538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 33638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 33738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 3381ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 3391ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 3400608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 3410608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Register ContentObserver to monitor the settings change. 3420608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo registerContentObserver(); 34338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3447ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 34538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 34625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 34725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 34825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 3490608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo private void onInitializeCecComplete(int initiatedBy) { 350fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 351fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 352fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 353fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 354fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 35525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3570608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 3580608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo int reason = -1; 3590608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo switch (initiatedBy) { 3600608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_BOOT_UP: 3610608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; 3620608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3630608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_ENABLE_CEC: 3640608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; 3650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3660608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_SCREEN_ON: 3670608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo case INITIATED_BY_WAKE_UP_MESSAGE: 3680608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; 3690608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo break; 3700608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 3710608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (reason != -1) { 3720608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(true, reason); 37325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 37425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 37525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 3765008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 3775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 3785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 3795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 3805008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 3815008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 3825008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 3845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 3855691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 3865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 3875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 3885008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 3925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 3935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 3945008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3955008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 396f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 3975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 3985008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 3995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 4005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 4015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 4025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 4035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 4045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 4065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 407350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 4085008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4095008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 4105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 4115008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 4125008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4135008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 41408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 4155008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4165008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 417f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 4185008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 4195008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4205008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4215008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4225008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 4245008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 4255008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4265008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4277ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 4287ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 4295008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 4307ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 4317ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 4327ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 4337ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 4345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 4355008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 437fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 4385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 439b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo initializeLocalDevices(initiatedBy); 440a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 441a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 442a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 443b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void initializeLocalDevices(final int initiatedBy) { 444a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 445b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // A container for [Device type, Local device info]. 446b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 447b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (int type : mLocalDevices) { 4486f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 4496f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (localDevice == null) { 4506f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim localDevice = HdmiCecLocalDevice.create(this, type); 4516f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 4523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 453b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo localDevices.add(localDevice); 454b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 4556f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // It's now safe to flush existing local devices from mCecController since they were 4566f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim // already moved to 'localDevices'. 4576f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim clearLocalDevices(); 458b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocateLogicalAddress(localDevices, initiatedBy); 459b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 460b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 461b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo @ServiceThreadOnly 462b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void allocateLogicalAddress(final ArrayList<HdmiCecLocalDevice> allocatingDevices, 463b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int initiatedBy) { 464b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo assertRunOnServiceThread(); 46589ec14e48f4a1bdf291cda9fba7b8172f55a2447Yuncheol Heo mCecController.clearLogicalAddress(); 466b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>(); 467b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo final int[] finished = new int[1]; 468b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (final HdmiCecLocalDevice localDevice : allocatingDevices) { 469b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo mCecController.allocateLogicalAddress(localDevice.getType(), 4703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 473c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 4743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 4753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 476410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 477410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 478410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 479410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 4803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 4813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 4823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 483b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo allocatedDevices.add(localDevice); 4843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 487b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (allocatingDevices.size() == ++finished[0]) { 488b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo if (initiatedBy != INITIATED_BY_HOTPLUG) { 489b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // In case of the hotplug we don't call onInitializeCecComplete() 490b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo // since we reallocate the logical address only. 4910608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo onInitializeCecComplete(initiatedBy); 492b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 493b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo notifyAddressAllocated(allocatedDevices, initiatedBy); 4943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 500a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 501b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo private void notifyAddressAllocated(ArrayList<HdmiCecLocalDevice> devices, int initiatedBy) { 502a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 503b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo for (HdmiCecLocalDevice device : devices) { 504b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int address = device.getDeviceInfo().getLogicalAddress(); 505fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 5063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5083ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 5100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 511a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5122b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 513a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 5150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 5170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 5180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 5190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 5200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 5222b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 5232b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5242b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 52530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 52630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 527e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 5282b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 52930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 53030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 531e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 5320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 53330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 53430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 535e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 5360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 537f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 538f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 539f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 540f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 541f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 5420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 543f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 5440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 545f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 546f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 547f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 548f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 549f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 550f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 551f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 552f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 553f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 554f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 555f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 556f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 557f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 5582b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5592b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 560f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 5610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5632738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 5642738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 5652738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 5662738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 5670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 5680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 5690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 5700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 5710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 5720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 5730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 5742b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 5750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 577e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 578401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 579401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 580401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 581401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 582401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 583401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 584401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 585c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 586401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 587401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 588401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 589401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 590401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 591401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 592401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 593401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 594401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 595401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 596401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 597c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 5982b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 599401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 600401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 60109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 6022b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 60309ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 60409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 605401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 606e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 607e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 608e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 609e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 610e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 611e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 612e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 613e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 614e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 615e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 616e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 617e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 618e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 619e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 620e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 62167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 622e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 623c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 624c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 6253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 6263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 6273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 6283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 6293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 6313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 6323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 6333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 6343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 6353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 6363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 638a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 63961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 6400340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 64179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 64279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 64379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 64479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 6458960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return tv.getCecDeviceInfo(logicalAddress); 646a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 647a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 6483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 649092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 650092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 651092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 652092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 653092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 654092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 655092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 65660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 65760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 65860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 659339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 6602b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 6612b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 66260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 66360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 66460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 66560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 66679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 66767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 66867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 66967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 67063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 67163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 67263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 67363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 67463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 67563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 67663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 67763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 67863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 67963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 68067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 681c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 682c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 683c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 684d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 685c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 686a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 687d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 688a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6894c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (mMessageValidator.isValid(command) == HdmiCecMessageValidator.OK) { 6905f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 6915f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 6922e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.error("Invalid message type:" + command); 6935f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 6945f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 6955f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 6965f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 697d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 698d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 699a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 700d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 701a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7025f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 703c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 704c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 7056aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 7066aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 7076aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 7086aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 7096aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 7106aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 7116aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 7126aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 7136aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 7146aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 7156aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 7166aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 717a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 718a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 719a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7204c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo int errorCode = mMessageValidator.isValid(message); 7214c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode != HdmiCecMessageValidator.OK) { 722a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // We'll not response on the messages with the invalid source or destination 723a95f1a9b89ba321f39fd9926388d157f831db9b2Yuncheol Heo // or with parameter length shorter than specified in the standard. 7244c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo if (errorCode == HdmiCecMessageValidator.ERROR_PARAMETER) { 7254c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo maySendFeatureAbortCommand(message, Constants.ABORT_INVALID_OPERAND); 7264c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo } 7274c212897813d6c23b2e7ffba4a4c01e13a41b1faYuncheol Heo return true; 72875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 729092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 730092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 731092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 73279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 73379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 73460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 73560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 736a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 737092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 738a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 739092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 74079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 741c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 742092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 743092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 744092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 74560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 746c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 7472e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Unhandled cec command:" + message); 7483a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 749092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 750a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 751a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 75267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 75367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 75467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 755ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 75667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 75767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 758a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 759ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 76060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 761b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 762b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (connected && !isTvDevice()) { 763b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); 764b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo for (int type : mLocalDevices) { 765b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); 766b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo if (localDevice == null) { 767b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice = HdmiCecLocalDevice.create(this, type); 768b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevice.init(); 769b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo } 770b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo localDevices.add(localDevice); 771b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 772b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); 773b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 774b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 77579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 776ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 77760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 778ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 77967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 78067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 78102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 78202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 78302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 78402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 78502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 7861de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 7870f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 78802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 7890f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 79002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 791a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7921de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 7931de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 794a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7951de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 7961de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 7970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7980f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 7990f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 800c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 8010f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 8020f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 8030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 804c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 8050f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 8060f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 8070f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 8080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 80902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 81002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 81160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 81260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 81360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 81460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 81560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 81679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 81779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 81879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 81979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 82079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 821b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 822b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 823b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 824b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 825b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 826b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 827b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 828b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 829b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 830b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 831b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 832b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 833b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 8341a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang AudioManager.FLAG_SHOW_UI | AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 835b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 8363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 8373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 838ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 839f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 840f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 841f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 842f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 843f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 844ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 845ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 846ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 847410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 84842c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 84942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 85061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 8512b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 8522b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 8533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 8543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 8557df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8567df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 8577df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 85893eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim // Hotplug event is used to add/remove MHL devices as TV input. 8597df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 8603b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); 8613b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); 8627df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 8637df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 8647df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 8657df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 86693eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); 86793eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 8687df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8693b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); 8707df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8717df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 87293eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 87393eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim updateSafeMhlInput(); 8747df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8757df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 8767df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8777df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 878ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 8797df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8807df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8817df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 882a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusModeChanged(int portId, int busmode) { 8837df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8843b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 8857df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 886a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setBusMode(busmode); 8877df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 888a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus mode change[portId:" + portId + 889a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim ", busmode:" + busmode + "]"); 8907df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8917df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8927df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8937df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 894a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlBusOvercurrent(int portId, boolean on) { 8957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8963b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 8977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 898a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.onBusOvercurrentDetected(on); 8997df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 900a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for bus overcurrent event[portId:" + portId + "]"); 9017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9037df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 9047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 905a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim void handleMhlDeviceStatusChanged(int portId, int adopterId, int deviceId) { 9067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 9073b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 908ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 9097df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 910a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim device.setDeviceStatusChange(adopterId, deviceId); 9117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 912a94417a51646a2560e44974c99435cb00bd96201Jinsuk Kim Slog.w(TAG, "No mhl device exists for device status event[portId:" 9137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 9147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 9167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 917ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 918ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 919ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 920ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 9213b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim SparseArray<HdmiMhlLocalDeviceStub> devices = mMhlController.getAllLocalDevices(); 922ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 9233b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = devices.valueAt(i); 924ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 925ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 926ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 927ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 928ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 929ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 930ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 931ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 932ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 933ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 934ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 935ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 936ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 937ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 938ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 939ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 940ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 941b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private class HdmiMhlVendorCommandListenerRecord implements IBinder.DeathRecipient { 942b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private final IHdmiMhlVendorCommandListener mListener; 943f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 944b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public HdmiMhlVendorCommandListenerRecord(IHdmiMhlVendorCommandListener listener) { 945f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 946f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 947f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 948f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 949f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 950b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.remove(this); 951f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 952f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 953f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 95478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 95578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 95678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 95778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 95878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 95978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 96078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 96178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 96378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 96478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 96578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 96678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 96778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 97078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 9726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 9736d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 9756d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 9766d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9786d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 979ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 9806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 9816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 9826d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 986ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 98738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 988ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 989ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 990ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 991ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 992ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 993ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 994ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 995ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 996ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 997ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 998ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 999ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1000ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1001119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 1002119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 1003119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 1004119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1005119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 1006119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 1007119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 1008119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1009119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1010119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1011119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 1012119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1013119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 1014119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1015119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1016119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1017119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 101812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 1019f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 1020f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1021f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 1022f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1023f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1024f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1025b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1026b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 1027b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1028f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 1029b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1030b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1031b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1032b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 103378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 103478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 103578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 103678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 103778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 103878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 103978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 104078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10410340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 10420340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 10430340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 10440340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 104578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 104778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 104878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 104978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 105061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 1051b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 10527e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 10537e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 10547e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 10557e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10567e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10577e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 10587e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 105961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 106061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 106161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 10627e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10637e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 106461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 106561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 10667e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10677e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10687e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10697e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 10707e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 10718960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1072a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1073a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1074a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1075a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 107672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 107772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 107872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 107972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 108079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1081a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1082a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1083c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1084a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1085a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 10863b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDeviceById(deviceId); 1087f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1088f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1089f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 109087f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 109187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1092f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1093f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1094f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1095f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 10967c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1097f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 109887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 10998960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1100a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1101a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1102a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1103a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1104a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1105a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1106a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1107a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1108a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1109a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 111072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 111172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 111272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 111372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1114a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1115a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1116a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1117c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1118a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1119a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 11208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1121a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1122a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1123a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1124a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1125a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1126c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1127a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1128a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1129a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1130a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 11313b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(mActivePortId); 1132f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1133f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1134f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 11354612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 11364612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 11374612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 11384612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 11394612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 11404612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 11414612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 11424612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1143a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1144a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1145a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1146a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1147a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1148a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 11497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 115078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11537fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11547fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 11557fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 115778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 115878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 115978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 116178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 11667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 116878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 116978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 117078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 117278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1173f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 117478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 117578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 117678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11777fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 117878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1179f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 118078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11826d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 11846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1185f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 11866d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 11906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 11912738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 11926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1193ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1194ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1195ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1196ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1197ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1198ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1199ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1200ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1201e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1202ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1203ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1204ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1205ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1206ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1207ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1208ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1209ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1210ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1211377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1212ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1213ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1214ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1215ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1216ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1217ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1218ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1219ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1220ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1221ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1222ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1223c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1224ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1225ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1226ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1227ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1228ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1229ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1230ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1231ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1232ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1233ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1234ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1235ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1236ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1237ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1238ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1239ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1240ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1241ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1242ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1243ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 124492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 124592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 12469c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 12479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 12499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 125261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 12539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 12559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 12569c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1257ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1258ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1259ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1260ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1261ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 12629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1265bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // Returns all the CEC devices on the bus including system audio, switch, 1266bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // even those of reserved type. 1267bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @Override 1268bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim public List<HdmiDeviceInfo> getDeviceList() { 1269bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim enforceAccessPermission(); 1270bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1271bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim synchronized (mLock) { 1272bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return (tv == null) 1273bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1274bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim : tv.getSafeCecDevicesLocked(); 1275bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1276bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1277bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 12789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 127941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 128041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 128141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 128241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 128341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 128441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 128541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 128641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 128741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 128841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 128941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 129041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 129141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 129241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 129341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 129441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 129541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 129641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 129741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 129841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 129941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 130041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 130141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 130241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 130341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 130441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 130541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 130641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 130741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 130841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 130941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 131041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 131141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1312a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1313a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1314a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1315a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1316a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1317a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1318a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 131938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1320a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1321a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1322a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1323a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1324a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1325160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1326160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 13274d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 13284d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 13294d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 13304d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 13314d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 13324d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 13334d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1334119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1335119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1336119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1337119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1338119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1339f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1340119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1341119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1342119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1343119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1344119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1345119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1346119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1347119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1348119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1349119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1350119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1351119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1352119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1353119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1354119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1355119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1356119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1357119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1358119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1359119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1360119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1361119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1362119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1363119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 136412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1365a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1366a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1367d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void sendStandby(final int deviceType, final int deviceId) { 1368d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim enforceAccessPermission(); 1369d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim runOnServiceThread(new Runnable() { 1370d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1371d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim public void run() { 1372d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1373d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (device == null) { 1374d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim Slog.w(TAG, "Local device not available"); 1375d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1376d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1377d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim device.sendStandby(deviceId); 1378d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1379d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim }); 1380d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1381d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 1382d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 138312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 1384b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 138512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1386b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1387b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1388b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1389b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1390b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1391b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1392b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1393b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1394b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1395b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1396b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1397b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1398b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1399b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1400b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1401b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1402b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1403b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1404b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1405b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1406b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1407b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1408b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1409b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1410b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1411b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1412b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1413b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1414b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1415b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1416a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1417a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1418a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1419b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1420b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1421b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1422b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1423b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1424b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1425b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1426b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1427b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1428b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1429b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1430b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1431b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1432bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1433bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1434bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1435b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1436b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1437b22d9ee0a364b10d488dd6a2e8ba69d5ca7f6258Jinsuk Kim enforceAccessPermission(); 1438b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1439b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1440b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1441b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1442b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1443b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1444b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1445b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1446b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1447b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1448a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1449f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1450f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1451b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void sendMhlVendorCommand(final int portId, final int offset, final int length, 1452f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1453f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1454f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1455f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1456f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1457f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1458f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1459f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1460f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 14613b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 1462f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1463f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1464f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1465f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1466b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlController.sendVendorCommand(portId, offset, length, data); 1467f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1468f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1469f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1470f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1471f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1472b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim public void addHdmiMhlVendorCommandListener( 1473b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim IHdmiMhlVendorCommandListener listener) { 1474f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1475b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiControlService.this.addHdmiMhlVendorCommandListener(listener); 1476f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1477959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1478959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1479959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1480959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1481959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1482959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1483959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1484959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1485959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1486959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1487959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1488959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1489959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1490959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1491959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1492959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1493959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1494959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1495959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1496959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1497959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1498959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 149978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 150078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1501a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 150279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 150379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 150479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 15057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 15067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1507c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 15087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 15097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 151079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 151178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 151278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1513a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 151479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 151579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 151679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 15177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 15187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1519c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 15207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 15217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 152279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 152378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 152478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 152578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 152678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 152778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 152878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 152978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 153078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 153178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 153278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 153378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 153478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 153578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 153678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 153778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 153878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 153978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 154078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 154178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 154278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 154378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 154478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 154578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 154678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 154778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 154878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 15497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 15506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 15514893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 15524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 15534893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 15544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 15554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 15564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 15574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 15594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 15604893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15614893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 15624893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 156361daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 15644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1565f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 15664893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1567f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 15684893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 15694893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 15706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15736d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1575ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1576ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1577ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1578ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1579ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1580ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1581ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1582ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1583ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1584ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1585ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1586ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1587ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1588ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1589ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1590ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1591ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1592ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1593ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1594ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1595ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1596ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1597ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1598ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1599ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1600ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1601ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 16029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1603f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1604f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1605f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1606f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1607f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1608f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 16099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 16109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 16119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1612f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 16139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 16179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 16189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1619f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 16209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 16219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 16229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 16239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 16249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 16259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 162961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 16309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1631f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 16329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1633f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 16349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 16359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 16369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 16409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 164112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1642b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1643f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1644b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 164512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1646b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 164712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1648b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1649b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1650b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1651b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1652b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1653b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1654f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 165512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1656f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 165712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 165812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1659b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1660b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1661b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1662b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1663b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1664b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1665326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeOneTouchRecordResult(int recorderAddress, int result) { 166612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1667f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 166812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1669326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(recorderAddress, result); 167012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 167112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 167212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 167312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 167412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 167512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 167612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1677326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeTimerRecordingResult(int recorderAddress, int result) { 167812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1679f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 168012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1681326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(recorderAddress, result); 168212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1683e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1684e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1685e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1686e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1687e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1688e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1689326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void invokeClearTimerRecordingResult(int recorderAddress, int result) { 1690e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1691f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1692e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1693326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(recorderAddress, 1694326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang result); 1695e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1696e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 169712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 169812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 169912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 170112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 17027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 17037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 17047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 17057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 17067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 17077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 17087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 170963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1710f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1711ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1712ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1713ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1714ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1715ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1716ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1717ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1718ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 17194893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 17204893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 172160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1722f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1723f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 172460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 172560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 172660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 172760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 17284893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 172960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 173060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 173160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 173260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 173360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 173460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1735e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1736e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 173779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 173861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 173979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 174079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1741e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1742b8d62e70bf2612e9c75bf7d8b2370f80e5877f95Yuncheol Heo return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); 1743e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1744e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 174579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1746c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 174761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 174860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1749a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1750a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1751a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1752a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 175392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 175492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 175592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 175692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 175792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 175892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 175938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1760f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 176138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1762f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 176338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 176438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 176538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1766f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 176738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1768f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1769c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1770c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 177138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 177238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1773f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 177438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1775f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1776c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1777c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 177838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 177938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1780f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 178138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1782f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1783c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 178438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 178538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 178638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 178738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 178838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1789fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 179038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 179138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 179238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 179338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 179438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 179538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 179638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 179738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 179838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 179938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 180038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 1801c12035cd40d01b032013f515cb509e6c8791cf65Jeff Brown pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 180238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 180338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 180438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 180538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 180638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 180738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 180838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1809c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 181038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1811a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1812fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1813fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1814fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1815fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1816fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1817a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 181838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 181938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 182038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 182138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 182238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 182338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 182438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 182538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 182638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1827c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 18280608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 18290608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); 18304fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 18324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 18334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 18344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 18354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 18364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 18374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 18384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 18394b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 18404b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 18414b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 18424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 18454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18471ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 18481ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 18491ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 18501ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 18511ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 18521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (isTvDevice()) { 18531ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 18541ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 18551ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 18561ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 1857f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 1858f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 1859f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1860f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 1861f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 1862f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 18634fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 1864350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 1865350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 1866350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 1867350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 186838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1869350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 1870f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 187138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 187238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 187338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 18744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 18754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 18764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 18774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 18784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 18804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 18814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 18844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 188538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 18864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 18874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1888c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 188938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 189038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1891c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 189238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 18934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 189438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 189538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 18965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 189738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 18984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1899119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1900119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1901119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1902119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1903119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1904119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1905119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1906119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1907119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1908119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1909119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1910119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1911119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 19120608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, 19130608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo byte[] params, boolean hasVendorId) { 1914119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1915d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (mVendorCommandListenerRecords.isEmpty()) { 1916d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return false; 1917d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1918119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1919119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1920119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1921119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1922119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 19230608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); 1924119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1925119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1926119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1927119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1928d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return true; 1929119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1930119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1931119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 19320608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { 19330608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo synchronized (mLock) { 19340608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (mVendorCommandListenerRecords.isEmpty()) { 19350608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return false; 19360608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19370608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 19380608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo try { 19390608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo record.mListener.onControlStateChanged(enabled, reason); 19400608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } catch (RemoteException e) { 19410608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); 19420608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19430608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19440608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo return true; 19450608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19460608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 19470608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo 1948b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { 1949b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim HdmiMhlVendorCommandListenerRecord record = 1950b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim new HdmiMhlVendorCommandListenerRecord(listener); 1951f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1952f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 1953f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1954f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 1955f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1956f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1957f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1958f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1959b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim mMhlVendorCommandListenerRecords.add(record); 1960f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1961f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1962f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1963b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim void invokeMhlVendorCommandListeners(int portId, int offest, int length, byte[] data) { 1964f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1965b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim for (HdmiMhlVendorCommandListenerRecord record : mMhlVendorCommandListenerRecords) { 1966f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1967f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 1968f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1969b3fbf9dbe8d41d91efbac2118b676af74592257bJinsuk Kim Slog.e(TAG, "Failed to notify MHL vendor command", e); 1970f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1971f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1972f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1973f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1974f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 19754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 19764d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 19774d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 19784d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 19794d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 19804d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 19814d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 19824d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 19834d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 19844d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 19854d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 19864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 1988350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 19895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 19905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 19915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 19925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 19935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 19945008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 19954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 19964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19970608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (!enabled) { 19980608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo // Call the vendor handler before the service is disabled. 19990608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo invokeVendorCommandListenersOnControlStateChanged(false, 20000608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); 20010608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo } 20025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 20035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 2004f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 20054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 20074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 20084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 20104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 2011fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 20124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 20134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 20144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 20154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 20164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 20174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 20184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 20204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 20214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 2022867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 2023867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 2024867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 2025867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 2026867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 2027e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2028e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 2029e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 2030e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 2031e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2032e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2033e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2034e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 2035e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2036e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 2037e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2038e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2039e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2040e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 2041e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2042e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 2043e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2044e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2045e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 2046e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 2047e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 2048e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 2049e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 2050e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 2051e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 2052e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 2053e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 2054e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 2055e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 2056e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @Override 2057e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim public void onComplete(int result) throws RemoteException { 2058e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 2059e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // This effectively sets the port to invalid one if the switching is for 2060e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // RAP[ContentOff]. 2061e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(lastInput); 2062e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 2063e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim }); 2064e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2065e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 2066e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 2067e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 2068e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2069e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 2070f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 2071e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 2072e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 20733b9309a01c9aa0544f97b2ec6abe7b254d829336Jinsuk Kim HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); 207493eed0c03a1f9cd66946760045122516483ba3f0Jinsuk Kim HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId); 2075e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 2076867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 207708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 2078e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 2079f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 208008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 208108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 208208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 208308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 208408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 208508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 208608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 208708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 208808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 208908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 209008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 2091339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 2092339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 2093339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 2094339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2095339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2096339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2097339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2098339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2099339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 21002e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 21012e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 21022e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 21032e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 21042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 21052e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 21062b0da5c4c84305f1d391dc78b85e244c9fd92456Yuncheol Heo intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); 21072e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 21082e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiControlService.PERMISSION); 21092e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 21100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2111