HdmiControlService.java revision 7c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8
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; 46f424932cfb1b16b01a37500d09e295912700a51dJungshik Jangimport android.hardware.hdmi.IHdmiMhlScratchpadCommandListener; 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"; 930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 94c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 9578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 96fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 97fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 98fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 99fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 100fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 101fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 102d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 103d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 104d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 105d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 106d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 107d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 108d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 109ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 115d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 116d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 117d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 118d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 11902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 12102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 12302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 12502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 12602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 12702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 12902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 13002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1311ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 132f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 13338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 13438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 135f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 13638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 13738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 13838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 14238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 14338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 14438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 14538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1471ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1481ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo String language = Locale.getDefault().getISO3Language(); 1491ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1501ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1511ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 15338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 16278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 16378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 16478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 16778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 168dbe6b45545dcd28e6aaf46986ed694196eb94de0Jungshik Jang private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG); 169dbe6b45545dcd28e6aaf46986ed694196eb94de0Jungshik Jang 17078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1714893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 17278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 17378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 17478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 175f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 1764893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1786d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1796d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 180f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 181119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 182119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 183119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 184119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 188b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 18912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 190b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 19192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 19292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 19392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 19492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 19592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1964d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 2004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 2014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 202ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 203ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 204ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 205ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2064893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2095008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 211f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 212f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 213f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2212b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 22230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2232b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2242b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 22530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2262b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 227e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 228e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 229e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 23075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 23175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 23238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 233c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 23438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 23538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2361ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2371ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2381ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 23938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 24038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 241fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 242fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 243fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 244867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 245867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 246867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 247f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Set to true while the input change by MHL is allowed. 248f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 249f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private boolean mMhlInputChangeEnabled; 250f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 251f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // List of records for MHL Scratchpad command listener to handle the caller killed in action. 252f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 253f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private final ArrayList<HdmiMhlScratchpadCommandListenerRecord> 254f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mScratchpadCommandListenerRecords = new ArrayList<>(); 255f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 256f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @GuardedBy("mLock") 257f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 258f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 259f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Nullable 260f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private HdmiMhlController mMhlController; 261f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 262f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Last input port before switching to the MHL port. Should switch back to this port 263f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // when the mobile device sends the request one touch play with off. 264e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 265e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 266e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 267e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2707d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2747d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2757d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2767d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2777d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2787d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2797d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2807d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2817d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 2827d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 2837d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2847d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2857d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 2867d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2877d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 2880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2902f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 291c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2927ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2937ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 29408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 2958b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 296a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 298347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 2995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 300347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 301a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 302a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 303fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 304a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 305a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 3060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 3070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3080792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 309e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 310f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (!mMhlController.isReady()) { 3110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 3120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 313ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 314f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 315f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim initPortInfo(); 31675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 3178692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 31863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 31938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 320f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mCecController != null) { 32138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 32238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 32338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 3241ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 3251ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 32638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3277ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 32838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 32925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 33025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 33125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 33225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private void onInitializeCecComplete() { 333fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 334fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 335fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 336fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 337fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 33825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim registerContentObserver(); 34125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 34225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 34325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 3445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 3455008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 3465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 3475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 3485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 3495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 3505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 3515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 3525008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 3535691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 3545008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 3555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 3565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3595008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 3605008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 3615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 3625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 364f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang // onChange is set up to run in service thread. 3655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 3665008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 3675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 3685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 3695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 3705008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 3715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 3725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3735008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 3745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 375350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 3765008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 3785008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 3795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 3805008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3815008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 38208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 385f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 3865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3885008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3895008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3915008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 3925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 3935008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3945008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3957ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 3967ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 3987ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 3997ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 4007ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 4017ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 4025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 4035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 4045008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 4055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void unregisterSettingsObserver() { 4065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); 4070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 408e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 409fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 4105008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 411fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeLocalDevices(mLocalDevices, initiatedBy); 412a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 413a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 414a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 415fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeLocalDevices(final List<Integer> deviceTypes, final int initiatedBy) { 416a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4173ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 4183ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 419fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final int[] finished = new int[1]; 4204b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo clearLocalDevices(); 4213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 4223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 4233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 4243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 4253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 428c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 4293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 4303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 431410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 432410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 433410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 434410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 4353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 4363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 4373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 4383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 4393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4414893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 442fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 443fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 444fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 4453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 451a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 452fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 453a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 4553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 4563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 457fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 4583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 4620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 463a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 465a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 4670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4680340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 4690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 4700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 4710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 4720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 4742b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 4752b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4762b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 47730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 47830c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 479e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 4802b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 48130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 48230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 483e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 4840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 48530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 48630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 487e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 4880340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 489f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 490f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 491f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 492f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (info.isMhlSupported()) { 493f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mhlSupportedPorts.add(info.getId()); 4940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 495f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 4960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 497f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. We can just use 498f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // cec port info if we do not have have port that supports MHL. 499f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.isEmpty()) { 500f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 501f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 502f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 503f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 504f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 505f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 506f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 507f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 508f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } else { 509f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim result.add(info); 5102b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5112b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 512f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mPortInfo = Collections.unmodifiableList(result); 5130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5152738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 5162738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 5172738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 5182738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 5190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 5200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 5210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 5220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 5230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 5240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 5250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 5262b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 5270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 529e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 530401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 531401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 532401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 533401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 534401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 535401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 536401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 537c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 538401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 539401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 540401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 541401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 542401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 543401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 544401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 545401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 546401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 547401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 548401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 549c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 5502b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 551401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 552401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 55309ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 5542b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 55509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 55609ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 557401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 558e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 559e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 560e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 561e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 562e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 563e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 564e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 565e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 566e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 567e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 568e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 569e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 570e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 571e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 572e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 57367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 574e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 575c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 576c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 5773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 5783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 5803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 5813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 5843ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 5853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 5873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 5883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 590a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 59161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 5920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 59379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 59479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 59579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 59679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 5978960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return tv.getCecDeviceInfo(logicalAddress); 598a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 599a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 6003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 601092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 602092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 603092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 604092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 605092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 606092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 607092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 60860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 60960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 61060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 611339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang int portId = pathToPortId(physicalAddress); 6122b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 6132b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 61460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 61660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 61879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 61967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 62067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 62167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 62263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 62363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 62463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 62563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 62663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 62763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 62863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 62963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 63063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 63163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 63267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 633c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 634c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 635c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 636d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 637c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 638a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 639d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 640a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6415f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (mMessageValidator.isValid(command)) { 6425f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 6435f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 644dbe6b45545dcd28e6aaf46986ed694196eb94de0Jungshik Jang mSpamSafeLogger.error("Invalid message type:" + command); 6455f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 6465f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 6475f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 6485f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 649d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 650d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 651a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 652d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 653a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6545f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 655c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 656c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 6576aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 6586aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 6596aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 6606aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 6616aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 6626aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 6636aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 6646aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 6656aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 6666aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 6676aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 6686aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 669a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 670a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 671a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 67275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 67375a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 67475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 675092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 676092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 677092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 67879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 67979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 68060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 68160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 682a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 683092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 684a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 685092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 68679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 687c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 688092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 689092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 690092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 69160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 692c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 693dbe6b45545dcd28e6aaf46986ed694196eb94de0Jungshik Jang mSpamSafeLogger.warning("Unhandled cec command:" + message); 6943a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 695092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 696a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 697a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 69867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 69967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 70067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 701ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 70267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 70367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 704a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 705ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 70660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 70779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 708ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 70960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 710ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 71167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 71267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 71302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 71402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 71502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 71602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 71702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 7181de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 7190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 72002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 7210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 72202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 723a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7241de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 7251de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 726a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7271de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 7281de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 7290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 7310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 732c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 7330f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 7340f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 7350f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 736c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 7370f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 7380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 7390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 74102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 74202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 74360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 74460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 74560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 74660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 74760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 74879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 74979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 75079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 75179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 75279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 753b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 754b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 755b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 756b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 757b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 758b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 759b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 760b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 761b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 762b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 763b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 764b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 765b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 766b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 767b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 768b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 7693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 771ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 772f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 773f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 774f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 775f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 776f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 777ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 778ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 779ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 780410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 78142c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 78242c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 78361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 7842b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 7852b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 7863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7887df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 789f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim void sendMhlSubcommand(int portId, HdmiMhlSubcommand command) { 790f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim assertRunOnServiceThread(); 791f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim sendMhlSubcommand(portId, command, null); 792f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 793f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 794f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @ServiceThreadOnly 795f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim void sendMhlSubcommand(int portId, HdmiMhlSubcommand command, SendMessageCallback callback) { 796f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim assertRunOnServiceThread(); 797f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.sendSubcommand(portId, command, callback); 798f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 799f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 800f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @ServiceThreadOnly 8017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang boolean handleMhlSubcommand(int portId, HdmiMhlSubcommand message) { 8027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8037df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8057df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return device.handleSubcommand(message); 8077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists[portId:" + portId + ", message:" + message); 8097df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return false; 8107df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 8147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 8167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice newDevice = new HdmiMhlLocalDevice(this, portId); 8177df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice oldDevice = mMhlController.addLocalDevice(newDevice); 8187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 8197df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 8207df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 8217df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8227df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId); 8247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 826ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // There is no explicit event for device removal unlike capability register event 827ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // used for device addition . Hence we remove the device on hotplug event. 8287c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo HdmiDeviceInfo deviceInfo = device.getInfo(); 8297c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo if (deviceInfo != null) { 8307c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE); 8317c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo updateSafeMhlInput(); 8327c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo } 8337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 8357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 837ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 8387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlCbusModeChanged(int portId, int cbusmode) { 8427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8447df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8457df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCbusMode(cbusmode); 8467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8477df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for cbus mode change[portId:" + portId + 8487df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang ", cbusmode:" + cbusmode + "]"); 8497df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8517df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8527df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8537df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlVbusOvercurrent(int portId, boolean on) { 8547df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8557df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8567df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8577df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onVbusOvercurrentDetected(on); 8587df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8597df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for vbus overcurrent event[portId:" + portId + "]"); 8607df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8617df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8627df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8637df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 864ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void handleMhlCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { 8657df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8667df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 867ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 868ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // Hotplug event should already have been called before capability register change event. 8697df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8707df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCapabilityRegister(adopterId, deviceId); 871ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE); 872ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim updateSafeMhlInput(); 8737df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8747df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for capability register change event[portId:" 8757df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 8767df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8777df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8787df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 879ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 880ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 881ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 882ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 883ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim SparseArray<HdmiMhlLocalDevice> devices = mMhlController.getAllLocalDevices(); 884ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 885ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiMhlLocalDevice device = devices.valueAt(i); 886ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 887ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 888ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 889ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 890ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 891ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 892ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 893ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 894ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 895ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 896ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 897ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 898ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 899ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 900ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 901ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 902ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 903f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private class HdmiMhlScratchpadCommandListenerRecord implements IBinder.DeathRecipient { 904f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim private final IHdmiMhlScratchpadCommandListener mListener; 905f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 906f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public HdmiMhlScratchpadCommandListenerRecord(IHdmiMhlScratchpadCommandListener listener) { 907f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mListener = listener; 908f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 909f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 910f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim @Override 911f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim public void binderDied() { 912f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mScratchpadCommandListenerRecords.remove(this); 913f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 914f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim } 915f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim 91678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 91778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 91878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 91978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 92078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 92178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 92278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 92378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 92478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 92578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 92678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 92778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 92878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 92978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 93078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 93178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 93278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9336d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 9346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 9356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 9376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 9386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9396d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9406d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 941ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 9426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 9436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 9446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9466d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 948ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 94938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 950ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 951ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 952ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 953ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 954ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 955ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 956ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 957ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 958ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 959ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 960ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 961ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 962ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 963119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 964119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 965119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 966119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 967119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 968119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 969119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 970119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 971119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 972119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 973119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 974119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 975119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 976119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 977119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 978119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 979119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 98012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 981f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 982f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 983f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 984f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 985f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 986f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 987b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 988b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 989b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 990f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 991b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 992b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 993b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 994b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 99578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 99678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 99778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 99878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 99978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 100078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 100178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 100278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 10030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 10040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 10050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 10060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 100778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 10080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 100978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 101078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 101178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 101261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 10137e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 10147e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 10157e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 10167e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10177e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10187e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 10197e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 102061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 102161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 102261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 10237e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10247e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 102561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 102661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 10277e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10287e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10297e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10307e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 10317e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 10328960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1033a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1034a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1035a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1036a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 103772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 103872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 103972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 104072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 104179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1042a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1043a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1044c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1045a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1046a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1047f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDeviceById(deviceId); 1048f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1049f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1050f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 105187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 105287f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 1053f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 1054f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the connected mobile device, start routing control to switch ports. 1055f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // callback is handled by MHL action. 1056f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.turnOn(callback); 10577c5d31ea93d6f6770c34f7a2a364522d8cc4b5d8Yuncheol Heo tv.doManualPortSwitching(device.getPortId(), null); 1058f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 105987f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 10608960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1061a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1062a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1063a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1064a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1065a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1066a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1067a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1068a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1069a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1070a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 107172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 107272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 107372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 107472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1075a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1076a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1077a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1078c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1079a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1080a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 10818333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1082a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1083a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1084a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1085a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1086a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1087c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1088a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1089a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1090a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1091a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 1092f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDevice(mActivePortId); 1093f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim if (device != null) { 1094f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim device.sendKeyEvent(keyCode, isPressed); 1095f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim return; 10964612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10974612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 10984612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 10994612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 11004612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 11014612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 11024612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 11034612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1104a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1105a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1106a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1107a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1108a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1109a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 11107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 111178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 11167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 111878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 111978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 112078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 112278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 11277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 112978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 113178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 113378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1134f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 113578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 113778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 113978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1140f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 114178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 11456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1146f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 11476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11486d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11496d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 11516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 11522738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 11536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1154ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1155ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1156ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1157ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1158ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1159ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1162e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1165ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1166ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1168ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1169ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1170ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1172377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1173ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1174ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1175ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1176ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1177ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1178ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1179ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1180ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1181ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1182ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1183ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1184c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1185ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1186ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1187ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1188ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1189ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1190ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1191ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1192ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1193ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1194ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1195ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1196ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1197ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1198ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1199ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1200ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1201ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1202ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1203ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1204ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 120592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 120692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 12079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 12089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 12109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 121361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 12149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 12169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 12179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1218ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1219ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1220ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1221ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1222ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 12239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 122741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 122841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 122941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 123041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 123141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 123241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 123341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 123441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 123541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 123641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 123741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 123841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 123941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 124041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 124141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 124241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 124341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 124441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 124541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 124641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 124741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 124841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 124941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 125041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 125141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 125241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 125341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 125441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 125541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 125641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 125741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 125841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 125941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1260a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1261a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1262a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1263a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1264a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1265a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1266a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 126738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1268a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1269a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1270a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1271a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1272a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1273160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1274160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 12754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 12764d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 12774d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 12784d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 12794d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12804d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 12814d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1282119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1283119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1284119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1285119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1286119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1287f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1288119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1289119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1290119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1291119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1292119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1293119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1294119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1295119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1296119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1297119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1298119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1299119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1300119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1301119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1302119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1303119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1304119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1305119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1306119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1307119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1308119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1309119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1310119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1311119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 131212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1313a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1314a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 131512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 131612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1317b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1318b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1319b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1320b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1321b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1322b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1323b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1324b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1325b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1326b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1327b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1328b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1329b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1330b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1331b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1332b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1333b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1334b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1335b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1336b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1337b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1338b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1339b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1340b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1341b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1342b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1343b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1344b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1345a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1346a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1347a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1348b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1349b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1350b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1351b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1352b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1353b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1354b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1355b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1356b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1357b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1358b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1359b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1360bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1361bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1362bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1363b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1364b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1365b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1366b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1367b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1368b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1369b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1370b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1371b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1372b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1373b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1374b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1375a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1376f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1377f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1378f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void sendScratchpadCommand(final int portId, final int offset, final int length, 1379f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1380f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1381f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1382f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1383f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1384f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1385f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1386f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1387f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1388f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 1389f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1390f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1391f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1392f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1393f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mMhlController.sendScratchpadCommand(portId, offset, length, data); 1394f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1395f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1396f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1397f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1398f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1399f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void addHdmiMhlScratchpadCommandListener( 1400f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang IHdmiMhlScratchpadCommandListener listener) { 1401f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1402f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHdmiMhlScratchpadCommandListener(listener); 1403f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1404959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1405959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1406959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(FileDescriptor fd, final PrintWriter writer, String[] args) { 1407959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 1408959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); 1409959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1410959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mHdmiControlEnabled: " + mHdmiControlEnabled); 1411959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mProhibitMode: " + mProhibitMode); 1412959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo if (mCecController != null) { 1413959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mCecController: "); 1414959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1415959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo mCecController.dump(pw); 1416959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1417959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1418959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPortInfo: "); 1419959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.increaseIndent(); 1420959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo for (HdmiPortInfo hdmiPortInfo : mPortInfo) { 1421959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("- " + hdmiPortInfo); 1422959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 1423959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.decreaseIndent(); 1424959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPowerStatus: " + mPowerStatus); 1425959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 142678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 142778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1428a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 142979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 143079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 143179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 14327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 14337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1434c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 14357fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 14367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 143779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 143878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 143978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1440a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 144179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 144279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 144379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 14447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 14457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1446c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 14477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 14487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 144979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 145078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 145178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 145278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 145378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 145478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 145578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 145678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 145778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 145878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 145978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 146078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 146178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 146278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 146378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 146478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 146578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 146678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 146778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 146878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 146978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 147078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 147178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 147278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 147378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 147478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 147578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 14767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 14776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 14784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 14794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 14804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 14814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 14834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 14844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 14864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 14874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 149061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 14914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1492f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 14934893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1494f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 14954893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14964893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 14976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 15016d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1502ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1503ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1504ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1505ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1506ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1507ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1508ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1509ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1510ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1511ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1512ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1513ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1514ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1515ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1516ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1517ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1518ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1519ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1520ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1521ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1522ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1523ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1524ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1525ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1526ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1527ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1528ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 15299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1530f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1531f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1532f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1533f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1534f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1535f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 15369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 15379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 15389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1539f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 15409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 15449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 15459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1546f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 15479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 15489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 15499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 15509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 15519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 15529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 155661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 15579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1558f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 15599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1560f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 15619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 15629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 15639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 156812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1569b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1570f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1571b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 157212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1573b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 157412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1575b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1576b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1577b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1578b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1579b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1580b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1581f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 158212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1583f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 158412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 158512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1586b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1587b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1588b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1589b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1590b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1591b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 159212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 159312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1594f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 159512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1596f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(result); 159712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 159812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 159912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 160412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 160512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1606f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 160712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1608f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(result); 160912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1610e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1611e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1612e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1613e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1614e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1615e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1616e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1617e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1618f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1619e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1620f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(result); 1621e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1622e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 162312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 162412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 162512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 162612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 162712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 16287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 16297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 16307fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 16317fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 16327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 16337fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 16347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 163563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1636f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1637ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1638ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1639ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1640ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1641ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1642ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1643ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1644ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 16454893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 16464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 164760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1648f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1649f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 165060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 165160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 165260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 165360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 16544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 165560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 165660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 165760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 165860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 165960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 166060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1661e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1662e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 166379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 166461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 166579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 166679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1667e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1668e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1669e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1670e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 167179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1672c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 167361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 167460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1675a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1676a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1677a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1678a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 167992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 168092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 168192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 168292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 168392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 168492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 168538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1686f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 168738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 1688f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 168938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 169038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 169138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1692f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 169338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1694f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1695c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1696c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 169738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 169838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1699f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 170038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1701f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1702c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1703c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 170438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 170538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1706f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 170738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1708f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1709c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 171038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 171138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 171238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 171338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 171438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1715fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 171638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 171738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 171838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 171938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 172038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 172138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 172238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 172338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 172438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 172538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 172638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 1727c12035cd40d01b032013f515cb509e6c8791cf65Jeff Brown pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 172838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 172938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 173038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 173138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 173238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 173338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 173438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1735c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 173638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1737a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1738fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1739fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1740fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1741fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1742fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1743a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 174438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 174538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 174638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 174738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 174838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 174938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 175038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 175138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 175238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1753c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 17544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 17564fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 17574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 17584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 17594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 17604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 17614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 17624fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 17634b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 17644b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 17654b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 17664fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17674fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17684fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 17694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17711ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 17721ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 17731ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 17741ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 17751ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 17761ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (isTvDevice()) { 17771ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 17781ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 17791ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 17801ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 1781f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 1782f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang String getLanguage() { 1783f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 1784f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang return mLanguage; 1785f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang } 1786f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang 17874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 1788350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 1789350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 1790350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 1791350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 1792350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (isTvDevice()) { 1793350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang unregisterSettingsObserver(); 1794350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 179538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1796350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 1797f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.clearAllLocalDevices(); 179838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 179938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 180038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 18014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 18024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 18034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 18044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 18054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 18074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 18084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 18114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 181238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 18134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 18144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1815c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 181638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 181738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1818c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 181938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 18204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 182138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 182238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 18235008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 182438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 18254d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1826119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1827119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1828119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1829119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1830119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1831119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1832119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1833119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1834119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1835119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1836119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1837119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1838119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1839119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1840119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1841119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1842119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1843119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1844119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1845119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1846119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1847119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1848119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1849119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1850119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1851119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1852119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1853119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1854119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1855f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void addHdmiMhlScratchpadCommandListener(IHdmiMhlScratchpadCommandListener listener) { 1856f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiMhlScratchpadCommandListenerRecord record = 1857f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang new HdmiMhlScratchpadCommandListenerRecord(listener); 1858f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1859f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 1860f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1861f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 1862f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1863f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1864f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1865f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1866f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords.add(record); 1867f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1868f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1869f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1870f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang void invokeScratchpadCommandListeners(int portId, int offest, int length, byte[] data) { 1871f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1872f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HdmiMhlScratchpadCommandListenerRecord record : 1873f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords) { 1874f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1875f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 1876f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1877f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.e(TAG, "Failed to notify scratchpad command", e); 1878f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1879f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1880f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1881f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1882f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 18834d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 18844d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 18854d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 18864d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18874d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18884d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 18894d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 18904d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 18914d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 18924d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18934d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 1896350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 18975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 18985008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 18995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 19005008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 19015008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 19025008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 19034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 19044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19055008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 19065008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 1907f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 19084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 19104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 19114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 19124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 19134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1914fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 19154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 19164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 19174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 19184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 19194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 19204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 19214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 19224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 19234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 19244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1925867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 1926867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 1927867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 1928867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 1929867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 1930e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1931e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 1932e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 1933e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 1934e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1935e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1936e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1937e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 1938e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1939e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 1940e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1941e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1942e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1943e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 1944e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1945e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 1946e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1947e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1948e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 1949e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 1950e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 1951e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 1952e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 1953e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 1954e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1955e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 1956e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1957e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 1958e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 1959e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @Override 1960e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim public void onComplete(int result) throws RemoteException { 1961e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 1962e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // This effectively sets the port to invalid one if the switching is for 1963e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // RAP[ContentOff]. 1964e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(lastInput); 1965e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1966e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim }); 1967e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1968e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 1969e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 1970e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 1971e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1972e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 1973f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim // the last port to go back to when turnoff command is received. Note that the last port 1974e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 1975e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 1976e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 1977e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim HdmiDeviceInfo info = (device != null && device.getInfo() != null) 1978e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim ? device.getInfo() 1979e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim : mPortDeviceMap.get(portId); 1980e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 1981867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 198208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 1983e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 1984f286b4d86b4b2ac91edb88d0336810e46d9a16ceJinsuk Kim mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 198508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 198608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 198708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 198808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 198908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 199008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 199108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 199208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 199308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 199408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 199508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 1996339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 1997339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 1998339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void displayOsd(int messageId) { 1999339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 2000339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); 2001339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); 2002339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang getContext().sendBroadcastAsUser(intent, UserHandle.ALL, 2003339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiControlService.PERMISSION); 2004339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 20050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 2006