HdmiControlService.java revision f424932cfb1b16b01a37500d09e295912700a51d
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; 700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 71a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 737e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 76b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 77b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 7878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 79f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 8102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 821ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heoimport java.util.Locale; 83a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 840792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 850792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 860792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 870792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 880792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 91c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 9278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 93fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 94fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 95fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 96fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 97fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 98fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 99d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 100d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 101d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 102d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 103d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 104d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 105d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 106ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 1074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 1084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 1094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 1104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 1114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 112d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 113d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 114d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 115d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 11602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 11702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 11802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 11902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 12002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 12102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 12202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 12302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 12402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 12502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 12602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 12702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 1281ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private class HdmiControlBroadcastReceiver extends BroadcastReceiver { 12938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 13038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 13138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 13238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 13338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 13438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 13538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 13638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 13738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 13838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 13938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 14038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 1421ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo case Intent.ACTION_CONFIGURATION_CHANGED: 1431ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo String language = Locale.getDefault().getISO3Language(); 1441ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (!mLanguage.equals(language)) { 1451ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo onLanguageChanged(language); 1461ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 1471ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo break; 14838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1550792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 15778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 15878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 15978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 16278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 16378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 16578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 16678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 16778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 168f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for device event listener to handle the caller killed in action. 1694893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1716d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 173f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for vendor command listener to handle the caller killed in action. 174119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 175119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 176119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 177119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 178f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang // List of records for MHL Scratchpad command listener to handle the caller killed in action. 1799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 180f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final ArrayList<HdmiMhlScratchpadCommandListenerRecord> 181f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords = new ArrayList<>(); 1829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 186b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 18712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 188b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 18992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 19092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 19192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 19292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 19392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1944d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1954d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1964d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 1994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 20008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo // Set to true while the input change by MHL is allowed. 20108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo @GuardedBy("mLock") 20208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo private boolean mMhlInputChangeEnabled; 20308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 204ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @GuardedBy("mLock") 205ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> mMhlDevices; 206ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 207ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 208ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 209ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 210ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 2114893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 2120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 2130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2145008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private final SettingsObserver mSettingsObserver; 2155008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 216f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final HdmiControlBroadcastReceiver 217f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mHdmiControlBroadcastReceiver = new HdmiControlBroadcastReceiver(); 218f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 2190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2200792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 2240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2292b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 23030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2312b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2322b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 23330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2342b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 235e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Map from port ID to HdmiDeviceInfo. 236e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private UnmodifiableSparseArray<HdmiDeviceInfo> mPortDeviceMap; 237e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 23875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 23975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 24038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 241c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 24238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 24338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 2441ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private String mLanguage = Locale.getDefault().getISO3Language(); 2451ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 2461ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 24738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 24838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 249fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 250fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 251fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 252867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 253867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang private int mActivePortId = Constants.INVALID_PORT_ID; 254867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 255e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Last input port before switching to the MHL port by way of incoming request RAP[ContentOn]. 256e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Should switch back to this port when the device sends RAP[ContentOff]. 257e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Gets invalidated if we go to other port/input. 258e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 259e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim private int mLastInputMhl = Constants.INVALID_PORT_ID; 260e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 2610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2637d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE)); 2645008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mSettingsObserver = new SettingsObserver(mHandler); 2650792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2677d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo private static List<Integer> getIntList(String string) { 2687d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo ArrayList<Integer> list = new ArrayList<>(); 2697d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(','); 2707d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo splitter.setString(string); 2717d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo for (String item : splitter) { 2727d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo try { 2737d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo list.add(Integer.parseInt(item)); 2747d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } catch (NumberFormatException e) { 2757d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo Slog.w(TAG, "Can't parseInt: " + item); 2767d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2777d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2787d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo return Collections.unmodifiableList(list); 2797d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo } 2807d9acc7a3eddb3e57c0b8312c3baf7ebb4f529d9Yuncheol Heo 2810792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2820792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2832f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 284c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2857ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2867ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 28708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); 2888b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 289a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 291347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 2925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, ENABLED); 293347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 294a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 295a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 296fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 297a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 298a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 3000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 302e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 3030792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 3040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 3050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 3062b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim initPortInfo(); 307ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = Collections.emptyList(); 30875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 3098692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 31063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 31138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 31238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 31338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 31438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 31538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 3161ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 3171ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); 31838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 3197ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 32038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 32125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 32225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 32325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 32425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private void onInitializeCecComplete() { 325fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 326fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 327fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 328fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 329fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 33025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 3315008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); 3325008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim registerContentObserver(); 33325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 33425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 33525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 3365008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void registerContentObserver() { 3375008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim ContentResolver resolver = getContext().getContentResolver(); 3385008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String[] settings = new String[] { 3395008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_ENABLED, 3405008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, 3415008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 3425008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_INPUT_SWITCHING_ENABLED, 3435008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.MHL_POWER_CHARGE_ENABLED 3445008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim }; 3455691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang for (String s : settings) { 3465008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim resolver.registerContentObserver(Global.getUriFor(s), false, mSettingsObserver, 3475008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim UserHandle.USER_ALL); 3485008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3495008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3505008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3515008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private class SettingsObserver extends ContentObserver { 3525008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public SettingsObserver(Handler handler) { 3535008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim super(handler); 3545008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3555008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3565008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @Override 3575008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim public void onChange(boolean selfChange, Uri uri) { 3585008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim String option = uri.getLastPathSegment(); 3595008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim boolean enabled = readBooleanSetting(option, true); 3605008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim switch (option) { 3615008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_ENABLED: 3625008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim setControlEnabled(enabled); 3635008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3645008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED: 3655008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoWakeup(enabled); 366350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang setCecOption(OPTION_CEC_AUTO_WAKEUP, toInt(enabled)); 3675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED: 3695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim tv().setAutoDeviceOff(enabled); 3705008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim // No need to propagate to HAL. 3715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3725008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_INPUT_SWITCHING_ENABLED: 37308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo setMhlInputChangeEnabled(enabled); 3745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3755008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim case Global.MHL_POWER_CHARGE_ENABLED: 37608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 37708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_POWER_CHARGE, toInt(enabled)); 37808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 3795008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim break; 3805008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3815008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3825008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3835008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3845008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private static int toInt(boolean enabled) { 3855008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return enabled ? ENABLED : DISABLED; 3865008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3875008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3887ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 3897ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3905008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim return Global.getInt(cr, key, toInt(defVal)) == ENABLED; 3917ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 3927ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 3937ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 3947ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 3955008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim Global.putInt(cr, key, toInt(value)); 3965008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 3975008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 3985008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim private void unregisterSettingsObserver() { 3995008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); 4000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 401e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 402fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 4035008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); 404fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeLocalDevices(mLocalDevices, initiatedBy); 405a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 406a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 407a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 408fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeLocalDevices(final List<Integer> deviceTypes, final int initiatedBy) { 409a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 4113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 412fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final int[] finished = new int[1]; 4134b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo clearLocalDevices(); 4143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 4153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 4163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 4173ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 4183ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 4193ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 4203ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 421c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 4223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 4233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 424410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 425410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 426410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 427410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 4283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 4293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 4303ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 4313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 4323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4344893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 435fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 436fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 437fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 4383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 4413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 444a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 445fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 446a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 4483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 4493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 450fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 4513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 4550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 456a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4572b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 458a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 4590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 4600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 4620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 4630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 4640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 4650340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 4672b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 4682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 4692b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 47030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 47130c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 472e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim SparseArray<HdmiDeviceInfo> portDeviceMap = new SparseArray<>(); 4732b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 47430c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 47530c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 476e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim portDeviceMap.put(info.getId(), new HdmiDeviceInfo(info.getAddress(), info.getId())); 4770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 47830c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 47930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 480e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mPortDeviceMap = new UnmodifiableSparseArray<>(portDeviceMap); 4810340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 482f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 483f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 484f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 485f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 486f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 487f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 488f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 489f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 490f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 491f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 4920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 494f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 495f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 496f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 497f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 498f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 499f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 500f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 501f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 502f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 5032b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 504f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 5052b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 5060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 5082738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang List<HdmiPortInfo> getPortInfo() { 5092738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return mPortInfo; 5102738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang } 5112738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang 5120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 5130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 5140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 5150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 5160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 5170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 5180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 5192b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 5200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 5210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 522e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 523401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 524401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 525401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 526401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 527401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 528401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 529401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 530c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 531401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 532401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 533401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 534401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 535401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 536401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 537401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 538401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 539401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 540401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 541401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 542c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 5432b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 544401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 545401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 54609ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 5472b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 54809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 54909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 550401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 551e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 552e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 553e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 554e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 555e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 556e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 557e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 558e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 559e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 560e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 561e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 562e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 563e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 564e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 565e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 56667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 567e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 568c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 569c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 5703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 5713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 5733ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 5743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 5763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 5773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 5783ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 5793ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 5803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 5813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 583a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 58461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 5850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 58679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 58779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 58879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 58979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 5908960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return tv.getCecDeviceInfo(logicalAddress); 591a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 592a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 5933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 594092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 595092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 596092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 597092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 598092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 599092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 600092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 60160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 60260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 60360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 6042b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 6052b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 6062b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 60760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 60860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 60960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 61060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 61179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 61267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 61367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 61467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 61563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 61663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 61763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 61863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 61963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 62063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 62163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 62263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 62363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 62463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 62567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 626c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 627c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 628c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 629d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 630c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 631a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 632d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 633a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6345f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (mMessageValidator.isValid(command)) { 6355f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 6365f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 6375f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang Slog.e(TAG, "Invalid message type:" + command); 6385f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 6395f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 6405f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 6415f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 642d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 643d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 644a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 645d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 646a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6475f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 648c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 649c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 6507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6517df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command) { 6527df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6537df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang sendMhlSubcommand(portId, command, null); 6547df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6557df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6567df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 6577df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void sendMhlSubcommand(int portId, HdmiMhlSubcommand command, SendMessageCallback callback) { 6587df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 6597df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang mMhlController.sendSubcommand(portId, command, callback); 6607df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 6617df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 6626aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 6636aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 6646aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 6656aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 6666aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 6676aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 6686aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 6696aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 6706aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 6716aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 6726aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 6736aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 674a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 675a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 676a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 67775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 67875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 67975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 680092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 681092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 682092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 68379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 68479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 68560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 68660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 687a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 688092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 689a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 690092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 69179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 692c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 693092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 694092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 695092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 69660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 697c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 6983a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 6993a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 700092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 701a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 702a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 70367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 70467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 70567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 706ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim * @param portId hdmi port number where hot plug event issued. 70767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 70867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 709a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 710ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void onHotplug(int portId, boolean connected) { 71160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 71279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 713ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim device.onHotplug(portId, connected); 71460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 715ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 71667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 71767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 71802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 71902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 72002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 72102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 72202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 7231de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 7240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 72502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 7260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 72702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 728a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7291de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 7301de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 731a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 7321de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 7331de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 7340f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7350f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 7360f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 737c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 7380f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 7390f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 7400f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 741c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 7420f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 7430f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 7440f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 7450f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 74602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 74702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 74860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 74960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 75060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 75160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 75260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 75379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 75479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 75579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 75679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 75779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 758b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 759b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 760b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 761b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 762b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 763b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 764b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 765b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 766b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 767b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 768b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 769b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 770b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 771b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 772b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 773b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 7743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 776ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 777f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 778f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (SystemAudioModeChangeListenerRecord record : 779f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mSystemAudioModeChangeListenerRecords) { 780f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeSystemAudioModeChangeLocked(record.mListener, enabled); 781f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 782ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 783ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 784ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 785410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 78642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 78742c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 78861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 7892b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 7902b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 7913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 7923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 7937df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 7947df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang boolean handleMhlSubcommand(int portId, HdmiMhlSubcommand message) { 7957df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 7967df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 7977df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 7987df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 7997df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return device.handleSubcommand(message); 8007df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8017df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists[portId:" + portId + ", message:" + message); 8027df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang return false; 8037df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8047df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8057df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8067df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlHotplugEvent(int portId, boolean connected) { 8077df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8087df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (connected) { 8097df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice newDevice = new HdmiMhlLocalDevice(this, portId); 8107df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice oldDevice = mMhlController.addLocalDevice(newDevice); 8117df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (oldDevice != null) { 8127df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang oldDevice.onDeviceRemoved(); 8137df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.i(TAG, "Old device of port " + portId + " is removed"); 8147df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8157df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8167df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.removeLocalDevice(portId); 8177df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8187df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onDeviceRemoved(); 819ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // There is no explicit event for device removal unlike capability register event 820ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // used for device addition . Hence we remove the device on hotplug event. 821ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); 822ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim updateSafeMhlInput(); 8237df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8247df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No device to remove:[portId=" + portId); 8257df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8267df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 827ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim announceHotplugEvent(portId, connected); 8287df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8297df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8307df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8317df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlCbusModeChanged(int portId, int cbusmode) { 8327df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8337df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8347df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8357df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCbusMode(cbusmode); 8367df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8377df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for cbus mode change[portId:" + portId + 8387df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang ", cbusmode:" + cbusmode + "]"); 8397df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8407df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8417df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8427df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 8437df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang void handleMhlVbusOvercurrent(int portId, boolean on) { 8447df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8457df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 8467df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8477df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.onVbusOvercurrentDetected(on); 8487df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8497df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for vbus overcurrent event[portId:" + portId + "]"); 8507df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8517df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8527df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 8537df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang @ServiceThreadOnly 854ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim void handleMhlCapabilityRegisterChanged(int portId, int adopterId, int deviceId) { 8557df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang assertRunOnServiceThread(); 8567df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 857ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 858ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim // Hotplug event should already have been called before capability register change event. 8597df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang if (device != null) { 8607df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang device.setCapabilityRegister(adopterId, deviceId); 861ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE); 862ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim updateSafeMhlInput(); 8637df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } else { 8647df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang Slog.w(TAG, "No mhl device exists for capability register change event[portId:" 8657df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); 8667df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8677df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang } 8687df52862dae1fa33c84725c613b0d9b88c1b28b6Jungshik Jang 869ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim @ServiceThreadOnly 870ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private void updateSafeMhlInput() { 871ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim assertRunOnServiceThread(); 872ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> inputs = Collections.emptyList(); 873ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim SparseArray<HdmiMhlLocalDevice> devices = mMhlController.getAllLocalDevices(); 874ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim for (int i = 0; i < devices.size(); ++i) { 875ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiMhlLocalDevice device = devices.valueAt(i); 876ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim HdmiDeviceInfo info = device.getInfo(); 877ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (info != null) { 878ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim if (inputs.isEmpty()) { 879ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs = new ArrayList<>(); 880ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 881ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim inputs.add(device.getInfo()); 882ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 883ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 884ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 885ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim mMhlDevices = inputs; 886ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 887ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 888ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 889ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim private List<HdmiDeviceInfo> getMhlDevicesLocked() { 890ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mMhlDevices; 891ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim } 892ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim 89378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 89478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 89578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 89678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 89778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 89878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 89978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 90078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 90178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 90278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 90378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 90478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 90578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 90678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 90778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 90878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 90978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 9106d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 9116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 9126d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9136d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 9146d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 9156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 9176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 918ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 9196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 9206d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 9216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9246d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 925ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 92638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 927ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 928ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 929ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 930ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 931ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 932ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 933ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 934ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 935ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 936ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 937ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 938ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 939ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 940119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 941119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 942119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 943119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 944119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 945119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 946119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 947119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 948119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 949119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 950119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 951119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 952119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 953119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 954119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 955119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 956119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 95712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 958f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiRecordListener mListener; 959f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 960f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiRecordListenerRecord(IHdmiRecordListener listener) { 961f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 962f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 963f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 964b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 965b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 966b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 967f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = null; 968b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 969b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 970b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 971b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 972f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private class HdmiMhlScratchpadCommandListenerRecord implements IBinder.DeathRecipient { 973f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiMhlScratchpadCommandListener mListener; 974f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 975f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public HdmiMhlScratchpadCommandListenerRecord(IHdmiMhlScratchpadCommandListener listener) { 976f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 977f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 978f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 979f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 980f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void binderDied() { 981f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords.remove(this); 982f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 983f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 984f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 98578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 98678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 98778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 98878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 98978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 99078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 99178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 99278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 9930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 9940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 9950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 9960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 99778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 9980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 99978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 100078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 100178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 100261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 10037e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 10047e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 10057e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 10067e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10077e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10087e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 10097e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 101061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 101161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 101261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 10137e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10147e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 101561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 101661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 10177e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10187e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 10197e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 10207e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 10217e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 10228960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim public void deviceSelect(final int deviceId, final IHdmiControlCallback callback) { 1023a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 1024a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 1025a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1026a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 102772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 102872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 102972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 103072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 103179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1032a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 1033a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1034c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1035a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 1036a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 103787f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim if (mMhlController != null) { 103887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDeviceById(deviceId); 103987f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim if (device != null) { 1040e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim if (device.getPortId() == tv.getActivePortId()) { 1041e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 1042e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return; 1043e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 104487f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // Upon selecting MHL device, we send RAP[Content On] to wake up 104587f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // the connected mobile device, start routing control to switch ports. 104687f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim // callback is handled by MHL action. 104787f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim device.turnOn(callback); 104887f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim tv.doManualPortSwitching(device.getInfo().getPortId(), null); 104987f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim return; 105087f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 105187f22a2870ac363a5849a7252c1bd44ce2b809c2Jinsuk Kim } 10528960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim tv.deviceSelect(deviceId, callback); 1053a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1054a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 1055a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 1056a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 1057a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 1058a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 1059a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1060a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1061a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1062a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 106372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 106472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 106572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 106672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 1067a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1068a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 1069a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 1070c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1071a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 1072a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 10738333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 1074a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1075a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1076a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1077a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1078a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1079c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 1080a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 1081a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 1082a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 1083a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 10844612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mMhlController != null) { 10854612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(mActivePortId); 10864612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (device != null) { 10874612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang device.sendKeyEvent(keyCode, isPressed); 10884612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 10894612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10904612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10914612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (mCecController != null) { 10924612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 10934612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang if (localDevice == null) { 10944612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang Slog.w(TAG, "Local device not available"); 10954612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang return; 10964612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang } 10974612a6e1116f1196e6aa64b5a6e3757ea48f94acJungshik Jang localDevice.sendKeyEvent(keyCode, isPressed); 1098a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1099a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1100a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 1101a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 1102a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 1103a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 11047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 110578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 11107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 111278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 111378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 111478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 111678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 11177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 11187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 11197fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 11207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 11217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 11227fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 112378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 112478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 112578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 112778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1128f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHotplugEventListener(listener); 112978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 113178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 11327fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 113378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 1134f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.removeHotplugEventListener(listener); 113578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 11396d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 1140f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addDeviceEventListener(listener); 11416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 11436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 11446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 11456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 11462738e2d872a22fe95a99941139863ff642fbd8e7Jungshik Jang return HdmiControlService.this.getPortInfo(); 11476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 1148ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1149ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1150ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 1151ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1152ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1153ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1154ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1155ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1156e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 1157ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1158ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1159ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 1161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1162ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 1165ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1166377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 1167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1168ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1169ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1170ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 1171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1172ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 1173ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1174ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 1175ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1176ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 1177ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 1178c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 1179ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1180ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1181ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 1182ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1183ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 1184ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1185ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1186ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1187ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 1188ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1189ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1190ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 1191ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1192ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1193ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 1194ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 1195ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 1196ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 1197ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 1198ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 119992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 120092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 12019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 12029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 12049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 120761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 12089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 12099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 12109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 12119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 1212ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim synchronized (mLock) { 1213ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> cecDevices = (tv == null) 1214ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim ? Collections.<HdmiDeviceInfo>emptyList() 1215ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim : tv.getSafeExternalInputsLocked(); 1216ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return HdmiUtils.mergeToUnmodifiableList(cecDevices, getMhlDevicesLocked()); 12179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 122141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 122241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 122341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 122441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 122541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 122641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 122741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 122841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 122941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 123041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 123141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 123241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 123341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 123441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 123541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 123641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 123741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 123841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 123941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 124041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 124141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 124241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 124341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 124441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 124541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 124641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 124741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 124841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 124941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 125041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 125141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 125241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 125341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1254a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1255a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1256a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1257a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1258a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1259a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1260a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 126138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1262a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1263a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1264a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1265a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1266a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1267160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1268160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 12694d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 12704d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 12714d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 12724d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 12734d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12744d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 12754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1276119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1277119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1278119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1279119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1280119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1281f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1282119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1283119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1284119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1285119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1286119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1287119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1288119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1289119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1290119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1291119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1292119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1293119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1294119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1295119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1296119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1297119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1298119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1299119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1300119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1301119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1302119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1303119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1304119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1305119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 130612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1307a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1308a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 130912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 131012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1311b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1312b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1313b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1314b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1315b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1316b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1317b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1318b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1319b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1320b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1321b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1322b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1323b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1324b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1325b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1326b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1327b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1328b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1329b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1330b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1331b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1332b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1333b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1334b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1335b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1336b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1337b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1338b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1339a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1340a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1341a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1342b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1343b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1344b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1345b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1346b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1347b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1348b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1349b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1350b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1351b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1352b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1353b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1354bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1355bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1356bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1357b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1358b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1359b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1360b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1361b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1362b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1363b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1364b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1365b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1366b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1367b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1368b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1369a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1370f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1371f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1372f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void sendScratchpadCommand(final int portId, final int offset, final int length, 1373f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang final byte[] data) { 1374f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1375f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang runOnServiceThread(new Runnable() { 1376f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1377f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void run() { 1378f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mMhlController == null) { 1379f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "No Mhl controller available."); 1380f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1381f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1382f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (!isControlEnabled()) { 1383f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Hdmi control is disabled."); 1384f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return ; 1385f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1386f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 1387f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (device == null) { 1388f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Invalid port id:" + portId); 1389f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1390f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1391f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mMhlController.sendScratchpadCommand(portId, offset, length, data); 1392f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1393f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang }); 1394f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1395f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1396f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang @Override 1397f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public void addHdmiMhlScratchpadCommandListener( 1398f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang IHdmiMhlScratchpadCommandListener listener) { 1399f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang enforceAccessPermission(); 1400f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiControlService.this.addHdmiMhlScratchpadCommandListener(listener); 1401f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 140278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 140378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1404a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 140579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 140679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 140779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 14087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 14097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1410c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 14117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 14127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 141379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 141478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 141578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1416a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 141779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 141879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 141979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 14207fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 14217fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1422c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 14237fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 14247fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 142579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 142678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 142778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 142878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 142978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 143078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 143178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 143278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 143378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 143478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 143578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 143678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 143778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 143878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 143978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 144078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 144178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 144278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 144378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 144478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 144578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 144678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 144778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 144878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 144978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 145078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 145178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 14527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 14536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 14544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 14554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 14564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 14574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14584893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 14594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 14604893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 14624893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 14634893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 14654893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 146661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, int status) { 14674893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 1468f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (DeviceEventListenerRecord record : mDeviceEventListenerRecords) { 14694893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 1470f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onStatusChanged(device, status); 14714893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 14724893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 14736d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14746d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14756d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14766d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 14776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1478ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1479ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1480ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1481ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1482ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1483ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1484ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1485ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1486ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1487ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1488ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1489ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1490ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1491ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1492ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1493ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1494ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1495ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1496ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1497ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1498ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1499ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1500ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1501ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1502ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1503ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1504ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 15059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 1506f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private final IHdmiInputChangeListener mListener; 1507f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1508f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang public InputChangeListenerRecord(IHdmiInputChangeListener listener) { 1509f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mListener = listener; 1510f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1511f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 15129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 15139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 15149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1515f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = null; 15169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 15209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 15219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1522f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord = new InputChangeListenerRecord(listener); 15239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 15249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 15259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 15269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 15279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 15289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 153261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 15339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 1534f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mInputChangeListenerRecord != null) { 15359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 1536f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mInputChangeListenerRecord.mListener.onChanged(info); 15379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 15389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 15399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 15439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 154412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1545b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1546f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(listener); 1547b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 154812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1549b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 155012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1551b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1552b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1553b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1554b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1555b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1556b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 1557f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 155812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1559f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return mRecordListenerRecord.mListener.getOneTouchRecordSource(recorderAddress); 156012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 156112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1562b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1563b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1564b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1565b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1566b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1567b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 156812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 156912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1570f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 157112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1572f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onOneTouchRecordResult(result); 157312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 157412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 157512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 157612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 157712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 157812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 157912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 158012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 158112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 1582f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 158312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 1584f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onTimerRecordingResult(result); 158512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1586e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1587e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1588e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1589e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1590e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1591e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1592e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1593e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1594f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang if (mRecordListenerRecord != null) { 1595e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1596f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mRecordListenerRecord.mListener.onClearTimerRecordingResult(result); 1597e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1598e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 159912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 160312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 16047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 16057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 16067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 16077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 16087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 16097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 16107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 161163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1612f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void invokeSystemAudioModeChangeLocked(IHdmiSystemAudioModeChangeListener listener, 1613ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1614ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1615ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1616ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1617ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1618ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1619ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1620ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 16214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 16224893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 162360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 1624f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 1625f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang invokeHotplugEventListenerLocked(record.mListener, event); 162660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 162760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 162860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 162960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 16304893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 163160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 163260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 163360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 163460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 163560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 163660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1637e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1638e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 163979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 164061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 164179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 164279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1643e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1644e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1645e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1646e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 164779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1648c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 164961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 165060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1651a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1652a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1653a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1654a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 165592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 165692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 165792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 165892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 165992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 166092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 166138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 166238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 166338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 166438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 166538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 166638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1667c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1668c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 166938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 167138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1672c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1673c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 167438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 167638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1677c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 167838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 168038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 168138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 168238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1683fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 168438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 168538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 168638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 168738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 168838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 168938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 169038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 169138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 169238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 169338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 169438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 1695c12035cd40d01b032013f515cb509e6c8791cf65Jeff Brown pm.goToSleep(SystemClock.uptimeMillis(), PowerManager.GO_TO_SLEEP_REASON_HDMI, 0); 169638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 169738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 169838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 169938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 17002849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo void nap() { 17012849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 17022849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo pm.nap(SystemClock.uptimeMillis()); 17032849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo } 17042849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo 170538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 170638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 170738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1708c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 170938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1710a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1711fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1712fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1713fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1714fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1715fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1716a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 171738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 171838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 171938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 172038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 172138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 172238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 172338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 172438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 172538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1726c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 17274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 17294fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 17304fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 17314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 17324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 17334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 17344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 17354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 17364b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 17374b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 17384b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 17394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 17424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17441ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 17451ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo private void onLanguageChanged(String language) { 17461ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 17471ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mLanguage = language; 17481ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 17491ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (isTvDevice()) { 17501ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo tv().broadcastMenuLanguage(language); 17511ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 17521ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 17531ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 17544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 1755350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mCecController != null) { 1756350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 1757350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 1758350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 1759350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (isTvDevice()) { 1760350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang unregisterSettingsObserver(); 1761350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang } 176238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1763350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang 1764350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang if (mMhlController != null) { 1765350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang mMhlController.clearAllLocalDevices(); 17665008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 176738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 176838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 176938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 17704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 17714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 17724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 17734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 17744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 17764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 17774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 17784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 17794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 17804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 178138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 17824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 17834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1784c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 178538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 178638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1787c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 178838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 17894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 179038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 179138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 17925008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED); 179338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 17944d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1795119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1796119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1797119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1798119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1799119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1800119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1801119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1802119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1803119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1804119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1805119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1806119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1807119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1808119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1809119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1810119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1811119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1812119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1813119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1814119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1815119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1816119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1817119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1818119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1819119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1820119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1821119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1822119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1823119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1824f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang private void addHdmiMhlScratchpadCommandListener(IHdmiMhlScratchpadCommandListener listener) { 1825f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang HdmiMhlScratchpadCommandListenerRecord record = 1826f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang new HdmiMhlScratchpadCommandListenerRecord(listener); 1827f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1828f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang listener.asBinder().linkToDeath(record, 0); 1829f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1830f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.w(TAG, "Listener already died."); 1831f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang return; 1832f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1833f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1834f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1835f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords.add(record); 1836f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1837f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1838f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 1839f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang void invokeScratchpadCommandListeners(int portId, int offest, int length, byte[] data) { 1840f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang synchronized (mLock) { 1841f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang for (HdmiMhlScratchpadCommandListenerRecord record : 1842f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang mScratchpadCommandListenerRecords) { 1843f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang try { 1844f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang record.mListener.onReceived(portId, offest, length, data); 1845f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } catch (RemoteException e) { 1846f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang Slog.e(TAG, "Failed to notify scratchpad command", e); 1847f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1848f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1849f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1850f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang } 1851f424932cfb1b16b01a37500d09e295912700a51dJungshik Jang 18524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 18534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 18544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 18554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 18584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 18594d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 18604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 18614d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 18634fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 1865350e68d0b80c22e6ec37dd683134f46079619803Jungshik Jang void setCecOption(int key, int value) { 18665008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim assertRunOnServiceThread(); 18675008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(key, value); 18685008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim } 18695008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim 18705008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim @ServiceThreadOnly 18715008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim void setControlEnabled(boolean enabled) { 18724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 18734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18745008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim int value = toInt(enabled); 18755008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mCecController.setOption(OPTION_CEC_ENABLE, value); 18764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 18775008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kim mMhlController.setOption(OPTION_MHL_ENABLE, value); 18784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 18814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 18824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 18844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1885fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 18864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 18874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 18884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 18894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 18904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 18914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 18924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 18944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 18954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1896867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang 1897867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang @ServiceThreadOnly 1898867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang void setActivePortId(int portId) { 1899867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang assertRunOnServiceThread(); 1900867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mActivePortId = portId; 1901e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1902e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Resets last input for MHL, which stays valid only after the MHL device was selected, 1903e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // and no further switching is done. 1904e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(Constants.INVALID_PORT_ID); 1905e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1906e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1907e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1908e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setLastInputForMhl(int portId) { 1909e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1910e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mLastInputMhl = portId; 1911e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1912e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1913e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1914e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim int getLastInputForMhl() { 1915e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1916e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim return mLastInputMhl; 1917e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1918e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1919e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim /** 1920e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * Performs input change, routing control for MHL device. 1921e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * 1922e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param portId MHL port, or the last port to go back to if {@code contentOn} is false 1923e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim * @param contentOn {@code true} if RAP data is content on; otherwise false 1924e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim */ 1925e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @ServiceThreadOnly 1926e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void changeInputForMhl(int portId, boolean contentOn) { 1927e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim assertRunOnServiceThread(); 1928e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim final int lastInput = contentOn ? tv().getActivePortId() : Constants.INVALID_PORT_ID; 1929e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().doManualPortSwitching(portId, new IHdmiControlCallback.Stub() { 1930e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim @Override 1931e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim public void onComplete(int result) throws RemoteException { 1932e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // Keep the last input to switch back later when RAP[ContentOff] is received. 1933e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // This effectively sets the port to invalid one if the switching is for 1934e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // RAP[ContentOff]. 1935e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim setLastInputForMhl(lastInput); 1936e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim } 1937e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim }); 1938e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1939e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // MHL device is always directly connected to the port. Update the active port ID to avoid 1940e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // unnecessary post-routing control task. 1941e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim tv().setActivePortId(portId); 1942e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim 1943e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // The port is either the MHL-enabled port where the mobile device is connected, or 1944e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // the last port to go back to when RAP[ContentOff] is received. Note that the last port 1945e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // may not be the MHL-enabled one. In this case the device info to be passed to 1946e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim // input change listener should be the one describing the corresponding HDMI port. 1947e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim HdmiMhlLocalDevice device = mMhlController.getLocalDevice(portId); 1948e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim HdmiDeviceInfo info = (device != null && device.getInfo() != null) 1949e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim ? device.getInfo() 1950e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim : mPortDeviceMap.get(portId); 1951e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim invokeInputChangeListener(info); 1952867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang } 195308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 1954e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim void setMhlInputChangeEnabled(boolean enabled) { 195508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo if (mMhlController != null) { 195608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlController.setOption(OPTION_MHL_INPUT_SWITCHING, toInt(enabled)); 195708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 195808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 195908a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 196008a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo mMhlInputChangeEnabled = enabled; 196108a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 196208a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 196308a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo 196408a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo boolean isMhlInputChangeEnabled() { 196508a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo synchronized (mLock) { 196608a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo return mMhlInputChangeEnabled; 196708a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 196808a1be81d7b597f858164fee6a4934264259b3aeYuncheol Heo } 19690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1970