HdmiControlService.java revision 410ca9c7a4a2d69af5c81e76320433bfda05cafe
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 190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.annotation.Nullable; 2038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.BroadcastReceiver; 217ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.content.ContentResolver; 220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 2338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 2438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 2561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 26c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 2760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 29c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiTvClient; 30d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 31d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 326d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 33d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 3512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.IHdmiRecordListener; 36ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 37119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kimimport android.hardware.hdmi.IHdmiVendorCommandListener; 38a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 3942c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 4067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 410792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 4278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 43e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 4438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 4578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 4638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 477ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 482b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kimimport android.util.ArraySet; 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 518b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 5278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 534893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 55a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 577e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kimimport com.android.server.hdmi.HdmiCecLocalDevice.ActiveSource; 584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 60b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 61b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 6278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 63f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 640340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 6502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 66a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 710792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 74c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 7578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 76fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo // The reason code to initiate intializeCec(). 77fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_ENABLE_CEC = 0; 78fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_BOOT_UP = 1; 79fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_SCREEN_ON = 2; 80fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo static final int INITIATED_BY_WAKE_UP_MESSAGE = 3; 81fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 82d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 83d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 84d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 85d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 86d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 87d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 88d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 89ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 95d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 96d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 97d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 98d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 9902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 10002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 10102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 10202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 10302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 10402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 10502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 10602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 10702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 10802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 10902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 11002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 11138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 11238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 11338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 11438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 11538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 11638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 11738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 11838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 12038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 12138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 12238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 12338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 12538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1300792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1310792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 13478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 13578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 13678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 13978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 14078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 14178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1424893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 14378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 14478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 14578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 14778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 14878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 14978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 160119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim // List of records for vendor command listener to handle the the caller killed in action. 161119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 162119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 163119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 164119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1689c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1699c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1709c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 171b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 17212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private IHdmiRecordListener mRecordListener; 173b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 174b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 17512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 176b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 17792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 17892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 17992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 18092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 18192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1824d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1834d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1844d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1854d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1864d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 1874d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 188ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 189ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 190ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 191ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 192ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 193ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 194ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 195ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1964893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1990792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 2010792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2020792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 2030792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 2040792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 2060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2092b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 21030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseIntArray mPortIdMap; 2112b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2122b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 21330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim private UnmodifiableSparseArray<HdmiPortInfo> mPortInfoMap; 2142b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 21575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 21675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 21738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 21838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 21938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 220c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 22138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 22238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 22338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 22438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 225fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo @ServiceThreadOnly 226fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private boolean mWakeUpMessageReceived = false; 227fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 2280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2290792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 2320792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2330792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2340792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2350792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2362f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 237c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2387ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2397ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 2408b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 241a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 243347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 244347a60449981fc934e5a84122df87c1447665548Yuncheol Heo mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, 245347a60449981fc934e5a84122df87c1447665548Yuncheol Heo HdmiTvClient.ENABLED); 246347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 247a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 248a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 249fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_BOOT_UP); 250a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 251a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2530792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2540792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 255e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2560792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2592b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim initPortInfo(); 26075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 2618692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 26263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 26338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 26438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 26538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 26638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 26738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 26838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 26938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2707ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 27138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 27225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo /** 27325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo * Called when the initialization of local devices is complete. 27425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo */ 27525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private void onInitializeCecComplete() { 276fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 277fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 278fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 279fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = false; 280fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo 28125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (isTvDevice()) { 28225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo mCecController.setOption(HdmiTvClient.OPTION_CEC_AUTO_WAKEUP, 28325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo tv().getAutoWakeup() ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED); 28425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 28525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 28625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 2877ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 2887ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 2897ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim return Global.getInt(cr, key, defVal ? Constants.TRUE : Constants.FALSE) == Constants.TRUE; 2907ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 2917ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 2927ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 2937ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 2947ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim Global.putInt(cr, key, value ? Constants.TRUE : Constants.FALSE); 2950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 296e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 297fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeCec(int initiatedBy) { 298a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, 299a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang HdmiTvClient.ENABLED); 300fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeLocalDevices(mLocalDevices, initiatedBy); 301a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 302a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 303a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 304fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void initializeLocalDevices(final List<Integer> deviceTypes, final int initiatedBy) { 305a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3063ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 3073ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 308fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final int[] finished = new int[1]; 3094b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo clearLocalDevices(); 3103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 3113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 3123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 3133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 3143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 3153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 3163ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 317c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 3183ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 3193ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 320410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // Set POWER_STATUS_ON to all local devices because they share lifetime 321410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // with system. 322410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType, 323410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiControlManager.POWER_STATUS_ON); 3243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 3253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 3263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 3273ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 3283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3304893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 331fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 332fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 333fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 3343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 3373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 340a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 341fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 342a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 3443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 3453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 346fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 3473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 3510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 352a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3532b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 354a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 3560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 3580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 3590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 3600340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 3610340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3620340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 3632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 3642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3652b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 36630c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseArray<HdmiPortInfo> portInfoMap = new SparseArray<>(); 36730c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim SparseIntArray portIdMap = new SparseIntArray(); 3682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 36930c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portIdMap.put(info.getAddress(), info.getId()); 37030c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim portInfoMap.put(info.getId(), info); 3710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 37230c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortIdMap = new UnmodifiableSparseIntArray(portIdMap); 37330c74d9ba60a7208a587ecd6dcdfef1cfbd7fce7Jinsuk Kim mPortInfoMap = new UnmodifiableSparseArray<>(portInfoMap); 3740340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 375f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 376f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 377f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 378f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 379f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 380f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 381f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 382f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 383f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 384f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 387f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 388f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 389f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 390f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 391f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 392f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 393f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 394f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 395f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3962b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 397f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 3982b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 4010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 4020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 4030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 4040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 4050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 4060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 4070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 4082b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 4090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 411e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 412401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 413401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 414401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 415401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 416401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 417401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 418401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 419c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 420401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 421401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 422401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 423401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 424401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 425401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 426401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 427401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 428401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 429401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 430401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 431c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 4322b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 433401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 434401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 43509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 4362b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 43709ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 43809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 439401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 440e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 441e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 442e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 443e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 444e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 445e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 446e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 447e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 448e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 449e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 450e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 451e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 452e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 453e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 454e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 45567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 456e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 457c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 458c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 4593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 4603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 4623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 4633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 4663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 4673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 4693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 4703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 472a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 47361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo(int logicalAddress) { 4740340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 47579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 47679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 47779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 47879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 47979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 480a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 481a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 4823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 483092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 484092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 485092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 486092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 487092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 488092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 489092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 49060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 49160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 49260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 4932b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 4942b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 4952b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 49660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 49760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 49860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 49960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 50079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 50167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 50267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 50367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 50463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 50563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 50663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 50763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 50863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 50963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 51063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 51163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 51467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 515c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 516c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 517c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 518d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 519c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 520a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 521d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 522a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5235f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (mMessageValidator.isValid(command)) { 5245f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang mCecController.sendCommand(command, callback); 5255f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } else { 5265f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang Slog.e(TAG, "Invalid message type:" + command); 5275f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang if (callback != null) { 5285f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang callback.onSendCompleted(Constants.SEND_RESULT_FAILURE); 5295f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 5305f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang } 531d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 532d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 533a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 534d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 535a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5365f75cbd8593e83eaf17cfac07186a3b6a7b7b1f1Jungshik Jang sendCecCommand(command, null); 537c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 538c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 5396aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 5406aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 5416aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 5426aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 5436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 5446aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 5456aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 5466aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 5476aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 5486aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 5496aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 5506aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 551a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 552a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 553a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 55475a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 55575a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 55675a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 557092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 558092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 559092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 56079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 56179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 56260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 56360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 564a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 565092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 566a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 567092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 56879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 569c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 570092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 571092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 572092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 57360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 574c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 5753a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 5763a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 577092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 578a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 579a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 58067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 58167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 58267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 5838b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 58467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 58567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 586a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 58767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 58979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 59079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 59160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 59260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 59367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 59467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 59502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 59602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 59702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 59802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 59902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 6001de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 6010f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 60202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 6030f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 60402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 605a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6061de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 6071de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 608a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6091de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 6101de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 6110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 6120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 6130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 614c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 6150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 6160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 6170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 618c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 6190f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 6200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 6210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 6220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 62302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 62402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 62560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 62660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 62760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 62860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 62960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 63079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 63179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 63279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 63379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 63479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 635b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 636b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 637b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 638b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 639b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 640b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 641b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 642b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 643b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 644b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 645b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 646b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 647b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 648b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 649b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 650b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 6513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 653ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 654ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 655ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 656ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 657ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 658ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 659410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang private HdmiDeviceInfo createDeviceInfo(int logicalAddress, int deviceType, int powerStatus) { 66042c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 66142c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 66261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(logicalAddress, 6632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 6642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 6653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 66778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 66878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 66978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 67078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 67178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 67278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 67378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 67478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 67578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 67678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 67778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 67878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 67978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 68078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 68178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 6856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 6866d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 6876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 6896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 6906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 693ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 6946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 6956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 6966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 6976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6986d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6996d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7006d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 701ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 70238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 703ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 704ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 705ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 706ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 707ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 708ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 709ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 710ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 711ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 712ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 713ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 714ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 715ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 716ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 717119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 718119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 719119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 720119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 721119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 722119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 723119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 724119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 725119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 726119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 727119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 728119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 729119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 730119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 731119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 732119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 733119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 73412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 735b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 736b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 737b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 73812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = null; 739b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 740b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 741b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 742b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 74378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 74478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 74578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 74678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 74778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 74878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 74978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 75078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7510340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 7520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 7530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 7540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 75578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 75778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 75978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 76061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public HdmiDeviceInfo getActiveSource() { 7617e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 7627e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 7637e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 7647e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 7657e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7667e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 7677e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 76861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activeSource.logicalAddress, 76961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang activeSource.physicalAddress, HdmiDeviceInfo.PORT_INVALID, 77061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo.DEVICE_INACTIVE, 0, ""); 7717e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7727e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 77361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang if (activePath != HdmiDeviceInfo.PATH_INVALID) { 77461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return new HdmiDeviceInfo(activePath, tv.getActivePortId()); 7757e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7767e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 7777e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7787e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 7797e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 780a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 781a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 782a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 783a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 784a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 78572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 78672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 78772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 78872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 78979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 790a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 791a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 792c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 793a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 794a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 795a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 796a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 797a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 798a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 799a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 800a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 801a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 802a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 803a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 804a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 805a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 80672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 80772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 80872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 80972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 810a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 811a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 812a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 813c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 814a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 815a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 8168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 817a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 818a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 819a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 820a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 821a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 822c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 823a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 824a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 825a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 826a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 827c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 828c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim if (localDevice == null) { 829c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "Local device not available"); 830a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 831a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 832c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim localDevice.sendKeyEvent(keyCode, isPressed); 833a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 834a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 835a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 836a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 837a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 8387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 83978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8427fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8437fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 8447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 84678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 84778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 84878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 85078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8537fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8547fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 8557fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 85778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 85878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 85978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 86178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 8667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 86878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 86978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 87078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 87278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8757fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 8777fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 87978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 8806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8826d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 8836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 8856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 886ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 8876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 8886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 8906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 8946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 8966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 897ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 898ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 899ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 900ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 901ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 902ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 903ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 904ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 905e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 906ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 907ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 908ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 909ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 910ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 911ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 912ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 913ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 914ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 915377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 916ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 917ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 918ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 919ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 920ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 921ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 922ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 923ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 924ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 925ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 926ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 927c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 928ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 929ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 930ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 931ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 932ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 933ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 934ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 935ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 936ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 937ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 938ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 939ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 940ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 941ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 942ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 943ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 944ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 945ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 946ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 947ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 94892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 94992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 9509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 9519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 9529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 9539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 9559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 95661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public List<HdmiDeviceInfo> getInputDevices() { 9579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 9589c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 9599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 9609c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 9619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 9629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 9639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 9659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 9679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 968160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setControlEnabled(final boolean enabled) { 96992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim enforceAccessPermission(); 97092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim runOnServiceThread(new Runnable() { 97192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 97292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim public void run() { 9734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang handleHdmiControlStatusChanged(enabled); 9744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 97592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 97692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim }); 97792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 978a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 979a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 98041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 98141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 98241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 98341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 98441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 98541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 98641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 98741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 98841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 98941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 99041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 99141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 99241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 99341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 99441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 99541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 99641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 99741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 99841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 99941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 100041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 100141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 100241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 100341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 100441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 100541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 100641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 100741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 100841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 100941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 101041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 101141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 101241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1013a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1014a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1015a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1016a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1017a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1018a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1019a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 102038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1021a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1022a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1023a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1024a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1025a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1026160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1027160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 1028160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setOption(final int key, final int value) { 10294d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 1030160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (!isTvDevice()) { 1031160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return; 1032160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1033160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim switch (key) { 1034c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP: 103525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo tv().setAutoWakeup(value == HdmiTvClient.ENABLED); 1036160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(key, value); 1037160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1038c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF: 1039160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // No need to pass this option to HAL. 1040c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim tv().setAutoDeviceOff(value == HdmiTvClient.ENABLED); 1041160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1042c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_INPUT_SWITCHING: // Fall through 1043c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_POWER_CHARGE: 1044160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 1045160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(key, value); 1046160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1047160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1048160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1049160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1050160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 10514d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @Override 10524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 10534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 10544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 10554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 10564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 10574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 10584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1059119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1060119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1061119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1062119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1063119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1064119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1065119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1066119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1067119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1068119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1069119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 1070119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1071119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1072119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1073119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1074119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1075119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1076119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1077119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1078119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1079119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1080119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1081119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1082119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1083119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1084119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1085119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1086119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1087119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1088119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1089119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1090119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1091119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1092119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1093119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 109412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1095a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1096a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 109712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 109812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1099b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1100b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1101b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1102b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1103b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1104b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1105b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1106b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1107b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1108b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1109b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1110b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1111b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1112b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1113b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1114b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1115b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1116b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1117b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1118b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1119b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1120b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1121b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1122b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1123b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1124b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1125b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1126b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1127a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1128a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1129a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1130b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1131b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1132b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1133b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1134b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1135b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1136b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1137b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1138b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1139b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1140b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1141b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1142bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1143bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1144bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1145b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1146b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1147b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1148b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1149b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1150b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1151b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1152b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1153b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1154b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1155b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1156b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1157a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 115878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 115978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1160a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 116179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 116279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 116379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 11647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 11657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1166c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11687fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 116979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 117078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 117178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1172a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 117379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 117479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 117579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 11767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 11777fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1178c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 118179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 118278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 118378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 118478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 118578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 118678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 118778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 118878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 118978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 119078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 119178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 119378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 119478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 119578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 119878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 119978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 120078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 120178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 120278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 120378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 120478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 120578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 120878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 12107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 12116d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 12124893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 12134893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 12144893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 12154893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 12164893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 12174893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 12184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 12204893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 12214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 12224893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12244893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 122561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeDeviceEventListeners(HdmiDeviceInfo device, boolean activated) { 12264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 12274893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 12284893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 12294893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 12304893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 12314893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 12326d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12336d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1237ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1238ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1239ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1240ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1241ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1242ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1243ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1244ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1245ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1246ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1247ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1248ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1249ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1250ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1251ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1252ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1253ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1254ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1255ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1256ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1257ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1258ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1259ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1260ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1261ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1262ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1263ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1264ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1265ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 12669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 12679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 12689c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 12699c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12709c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 12719c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12729c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12739c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12749c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12759c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 12769c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12779c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 12789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 12799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 12809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 12829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 12839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12849c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 12859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 128861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void invokeInputChangeListener(HdmiDeviceInfo info) { 12899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 12919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 129272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mInputChangeListener.onChanged(info); 12939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 12959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 130012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1301b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 130212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(); 1303b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 130412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1305b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 130612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1307b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 130812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = listener; 1309b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1310b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1311b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1312b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1313b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 131412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 131512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 131612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return mRecordListener.getOneTouchRecordSource(recorderAddress); 131712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 131812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1319b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1320b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1321b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1322b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1323b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1324b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 132512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 132612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 132712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 132812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 132912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onOneTouchRecordResult(result); 133012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 133112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 133212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 133712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 133812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 133912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 134012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 134112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onTimerRecordingResult(result); 134212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1343e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1344e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1345e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1346e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1347e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1348e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1349e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1350e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1351e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (mRecordListener != null) { 1352e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1353e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mRecordListener.onClearTimerRecordingResult(result); 1354e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1355e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 135612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 136012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 13617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 13627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 13637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 13647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 13657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 13667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 136863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1369ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1370ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1371ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1372ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1373ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1374ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1375ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1376ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1377ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 13784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 13794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 138060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 138160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 13824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 138360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 13874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 138860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 138960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 139060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 139160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 139260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 139360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1394e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1395e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 139679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 139761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_TV); 139879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 139979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1400e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1401e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1402e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1403e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 140479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1405c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 140661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang mCecController.getLocalDevice(HdmiDeviceInfo.DEVICE_PLAYBACK); 140760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1408a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1409a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1410a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1411a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 141292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 141392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 141492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 141592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 141692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 141792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 141838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 141938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 142038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 142138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 142338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1424c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1425c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 142638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 142838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1429c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1430c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 143138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 143238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 143338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1434c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 143538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 143638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 143738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 143838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 143938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1440fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 144138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 144238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 144338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 144438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 144538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 144638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 144738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 144838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 144938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 145038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 145138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 145238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 145338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 145438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 145538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 145638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 14572849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo void nap() { 14582849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 14592849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo pm.nap(SystemClock.uptimeMillis()); 14602849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo } 14612849b7ccd1cf973f862dd9b95355afbc9ca9268bYuncheol Heo 146238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 146338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 146438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1465c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 146638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1467a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1468fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1469fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1470fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1471fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1472fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1473a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 147438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 147538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 147638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 147738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 147838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 147938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 148038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 148138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 148238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1483c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 14844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 14864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 14874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 14884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 14894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 14904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 14914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 14924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 14934b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 14944b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 14954b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 14964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 14994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 150238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 15034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 150438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 150538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 150638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 150738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 15084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 15094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 15114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 15124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 15144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 15154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 15184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 151938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 15204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 15214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1522c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 152338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 152438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1525c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 152638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 15274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 152838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 152938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 1530c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.DISABLED); 153138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15324d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1533119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1534119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1535119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1536119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1537119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1538119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1539119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1540119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1541119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1542119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1543119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1544119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1545119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1546119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1547119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1548119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1549119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1550119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1551119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1552119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1553119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1554119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1555119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1556119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1557119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1558119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1559119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1560119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1561119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 15624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 15634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 15644d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 15654d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15664d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15674d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 15684d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 15694d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 15704d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 15714d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15724d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 15754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void handleHdmiControlStatusChanged(boolean enabled) { 15764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang int value = enabled ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED; 15794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, value); 15804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 15814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mMhlController.setOption(HdmiTvClient.OPTION_MHL_ENABLE, value); 15824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 15854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 15864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1589fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 15904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 15914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 15924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 15934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 15944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 15964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 15984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16000792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1601