HdmiControlService.java revision 6aae6528a6672497b1d1dffb5c083093d5c46dc8
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; 25c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 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. 21026ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo private final SparseIntArray mPortIdMap = new SparseIntArray(); 2112b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2122b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 21326ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo private final SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>(); 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 { 3203ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 3213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 3223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 3233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 3243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 3253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3263ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3274893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 328fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (deviceTypes.size() == ++finished[0]) { 329fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onInitializeCecComplete(); 330fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo notifyAddressAllocated(devices, initiatedBy); 3313ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 3343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3363ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 337a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 338fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, int initiatedBy) { 339a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 3413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 3423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 343fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo device.handleAddressAllocated(address, initiatedBy); 3443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 3480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 349a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3502b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 351a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 3530340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 3550340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 3560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 3570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 3580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3590340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 3602b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 3612b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3622b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 3632b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 3642b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim mPortIdMap.put(info.getAddress(), info.getId()); 3652b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim mPortInfoMap.put(info.getId(), info); 3660340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3670340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 368f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 369f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 370f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 371f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 372f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 373f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 374f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 375f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 376f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 377f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 380f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 381f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 382f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 383f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 384f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 385f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 386f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 387f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 388f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3892b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 390f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 3912b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 3950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 3960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 3970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 3980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 3990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 4002b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 4010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 4022b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 4032b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 4040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 4050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 406e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 407401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 408401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 409401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 4102b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 411401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 4122b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 413401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 414401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 415401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 416c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 417401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 418401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 419401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 420401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 421401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 422401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 423401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 424401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 425401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 426401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 4272b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 428401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 4292b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 430c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 4312b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 432401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 433401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 4342b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 43509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 4362b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 4372b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 43809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 43909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 440401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 441e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 442e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 443e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 444e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 445e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 446e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 447e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 448e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 449e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 450e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 451e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 452e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 453e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 454e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 455e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 45667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 457e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 458c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 459c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 4603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 4613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 4633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 4643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 4673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 4683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 4703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 4713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 473a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 474a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 4750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 47679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 47779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 47879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 47979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 48079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 481a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 482a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 4833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 484092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 485092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 486092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 487092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 488092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 489092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 490092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 49160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 49260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 4932b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 49460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 4952b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 4962b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 4972b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 4982b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 49960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 50060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 50160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 50260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 50379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 50467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 50567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 50667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 50763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 50863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 50963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 51163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 51263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 51363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 51463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 51663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 51767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 518c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 519c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 520c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 521d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 522c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 523a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 524d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 525a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 526d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 527d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 528d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 529a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 530d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 531a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 532d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 533c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 534c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 5356aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo /** 5366aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * Send <Feature Abort> command on the given CEC message if possible. 5376aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * If the aborted message is invalid, then it wont send the message. 5386aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param command original command to be aborted 5396aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo * @param reason reason of feature abort 5406aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo */ 5416aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo @ServiceThreadOnly 5426aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo void maySendFeatureAbortCommand(HdmiCecMessage command, int reason) { 5436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo assertRunOnServiceThread(); 5446aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mCecController.maySendFeatureAbortCommand(command, reason); 5456aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo } 5466aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo 547a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 548a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 549a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 55075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 55175a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 55275a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 553092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 554092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 555092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 55679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 55779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 55860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 55960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 560a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 561092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 562a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 563092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 56479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 565c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 566092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 567092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 568092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 56960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 570c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 5713a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 5723a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 573092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 574a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 575a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 57667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 57767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 57867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 5798b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 58067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 58167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 582a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 58367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 58460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 58579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 58679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 58760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 58967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 59067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 59102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 59202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 59302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 59402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 59502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 5961de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 5970f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 59802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 5990f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 60002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 601a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6021de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 6031de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 604a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 6051de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 6061de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 6070f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 6080f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 6090f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 610c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 6110f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 6120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 6130f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 614c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 6150f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 6160f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 6170f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 6180f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 61902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 62002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 62160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 62260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 62360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 62460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 62560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 62679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 62779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 62879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 62979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 63079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 631b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 632b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 633b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 634b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 635b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 636b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 637b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 638b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 639b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 640b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 641b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 642b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 643b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 644b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 645b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 646b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 6473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 649ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 650ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 651ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 652ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 653ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 654ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 6553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 65642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 65742c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 6583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 6592b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 6602b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 6613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 66378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 66478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 66578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 66678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 66778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 66878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 66978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 67078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 67178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 67278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 67378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 67478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 67578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 67678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 67778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 67878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 67978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 6816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 6826d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 6836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 6856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 6866d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 689ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 6906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 6916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 6926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 6936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 697ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 69838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 699ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 700ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 701ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 702ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 703ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 704ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 705ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 706ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 707ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 708ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 709ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 710ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 711ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 712ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 713119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 714119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 715119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 716119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 717119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 718119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 719119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 720119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 721119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 722119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 723119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 724119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 725119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 726119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 727119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 728119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 729119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 73012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 731b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 732b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 733b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 73412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = null; 735b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 736b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 737b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 738b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 73978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 74078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 74178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 74278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 74378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 74478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 74578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 74678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7470340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 7480340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 7490340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 7500340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 75178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7520340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 75378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 75478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 75578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7567e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim public HdmiCecDeviceInfo getActiveSource() { 7577e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 7587e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (tv == null) { 7597e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim Slog.w(TAG, "Local tv device not available"); 7607e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 7617e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7627e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim ActiveSource activeSource = tv.getActiveSource(); 7637e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activeSource.isValid()) { 7647e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return new HdmiCecDeviceInfo(activeSource.logicalAddress, 7657e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim activeSource.physicalAddress, HdmiCecDeviceInfo.PORT_INVALID, 7667e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim HdmiCecDeviceInfo.DEVICE_INACTIVE, 0, ""); 7677e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7687e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim int activePath = tv.getActivePath(); 7697e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim if (activePath != HdmiCecDeviceInfo.PATH_INVALID) { 7707e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return new HdmiCecDeviceInfo(activePath, tv.getActivePortId()); 7717e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7727e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim return null; 7737e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim } 7747e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim 7757e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim @Override 776a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 777a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 778a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 779a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 780a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 78172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 78272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 78372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 78472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 78579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 786a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 787a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 788c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 789a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 790a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 791a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 792a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 793a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 794a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 795a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 796a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 797a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 798a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 799a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 800a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 801a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 80272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (callback == null) { 80372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim Slog.e(TAG, "Callback cannot be null"); 80472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 80572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 806a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 807a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 808a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 809c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 810a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 811a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 8128333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 813a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 814a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 815a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 816a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 817a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 818c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 819a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 820a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 821a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 822a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 823c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 824c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim if (localDevice == null) { 825c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "Local device not available"); 826a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 827a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 828c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim localDevice.sendKeyEvent(keyCode, isPressed); 829a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 830a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 831a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 832a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 833a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 8347fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 83578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8367fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 8407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 84278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 84378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 84478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8457fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 84678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8477fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8487fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8497fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8507fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 8517fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8527fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 85378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 85478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 85578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8567fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 85778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8587fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8597fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 8627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 86478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 86578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 86678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 86878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8697fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8707fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 8737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8747fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 87578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 8766d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8776d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8786d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 8796d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 8816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 882ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 8836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 8846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 8866d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 8906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 8926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 893ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 894ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 895ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 896ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 897ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 898ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 899ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 900ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 901e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 902ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 903ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 904ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 905ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 906ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 907ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 908ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 909ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 910ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 911377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 912ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 913ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 914ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 915ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 916ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 917ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 918ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 919ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 920ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 921ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 922ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 923c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 924ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 925ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 926ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 927ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 928ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 929ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 930ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 931ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 932ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 933ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 934ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 935ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 936ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 937ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 938ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 939ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 940ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 941ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 942ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 943ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 94492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 94592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 9469c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 9479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 9489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 9499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 9519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 9529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public List<HdmiCecDeviceInfo> getInputDevices() { 9539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 9549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 9559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 9569c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 9579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 9589c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 9599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9609c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 9619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 9639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 964160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setControlEnabled(final boolean enabled) { 96592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim enforceAccessPermission(); 96692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim runOnServiceThread(new Runnable() { 96792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 96892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim public void run() { 9694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang handleHdmiControlStatusChanged(enabled); 9704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 97192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 97292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim }); 97392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 974a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 975a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 97641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 97741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 97841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 97941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 98041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 98141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 98241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 98341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 98441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 98541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 98641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 98741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 98841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 98941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 99041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 99141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 99241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 99341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 99441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 99541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 99641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 99741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 99841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 99941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 100041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 100141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 100241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 100341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 100441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 100541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 100641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 100741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 100841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 1009a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 1010a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 1011a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 1012a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 1013a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 1014a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 1015a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 101638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 1017a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1018a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1019a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1020a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 1021a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1022160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 1023160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 1024160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setOption(final int key, final int value) { 10254d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 1026160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (!isTvDevice()) { 1027160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return; 1028160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1029160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim switch (key) { 1030c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP: 103125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo tv().setAutoWakeup(value == HdmiTvClient.ENABLED); 1032160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(key, value); 1033160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1034c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF: 1035160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // No need to pass this option to HAL. 1036c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim tv().setAutoDeviceOff(value == HdmiTvClient.ENABLED); 1037160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1038c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_INPUT_SWITCHING: // Fall through 1039c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_POWER_CHARGE: 1040160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 1041160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(key, value); 1042160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1043160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 1044160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1045160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 1046160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 10474d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @Override 10484d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 10494d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 10504d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 10514d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 10524d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 10534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 10544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1055119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1056119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1057119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 1058119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 1059119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1060119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1061119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1062119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1063119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1064119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1065119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 1066119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1067119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1068119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1069119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1070119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1071119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1072119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1073119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1074119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1075119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1076119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1077119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1078119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1079119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1080119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1081119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1082119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1083119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1084119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1085119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1086119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1087119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1088119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1089119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 109012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1091a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1092a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 109312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 109412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1095b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1096b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1097b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1098b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1099b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1100b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1101b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1102b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1103b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1104b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1105b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1106b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1107b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1108b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1109b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1110b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1111b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1112b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1113b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1114b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1115b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1116b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1117b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1118b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1119b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1120b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1121b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1122b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1123a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1124a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1125a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1126b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1127b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1128b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1129b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1130b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1131b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1132b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1133b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1134b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1135b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1136b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1137b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1138bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1139bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1140bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1141b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1142b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1143b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1144b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1145b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1146b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1147b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1148b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1149b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1150b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1151b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1152b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1153a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 115478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 115578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1156a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 115779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 115879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 115979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 11607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 11617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1162c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 116579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 116678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 116778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1168a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 116979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 117079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 117179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 11727fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 11737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1174c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11757fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 117779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 117878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 117978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 118078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 118178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 118278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 118378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 118478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 118578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 118678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 118778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 118878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 118978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 119078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 119178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 119378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 119478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 119578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 119678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 119778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 119878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 119978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 120078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 120178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 120478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 120578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 12067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 12076d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 12084893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 12094893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 12104893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 12114893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 12124893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 12134893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 12144893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 12164893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 12174893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 12184893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12194893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 12204893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 12214893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 12224893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 12234893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 12244893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 12254893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 12264893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 12274893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 12286d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12296d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12306d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 12326d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1233ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1234ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1235ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1236ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1237ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1238ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1239ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1240ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1241ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1242ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1243ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1244ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1245ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1246ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1247ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1248ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1249ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1250ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1251ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1252ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1253ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1254ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1255ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1256ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1257ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1258ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1259ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1260ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1261ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 12629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 12639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 12649c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 12659c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12669c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 12679c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12689c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12699c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12709c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12719c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 12729c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12739c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 12749c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 12759c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 12769c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12779c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 12789c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 12799c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12809c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 12819c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12829c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12839c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 128472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void invokeInputChangeListener(HdmiCecDeviceInfo info) { 12859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 12879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 128872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mInputChangeListener.onChanged(info); 12899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 12919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 129612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1297b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 129812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(); 1299b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 130012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1301b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 130212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1303b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 130412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = listener; 1305b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1306b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1307b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1308b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1309b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 131012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 131112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 131212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return mRecordListener.getOneTouchRecordSource(recorderAddress); 131312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 131412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1315b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1316b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1317b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1318b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1319b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1320b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 132112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 132212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 132312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 132412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 132512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onOneTouchRecordResult(result); 132612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 132712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 132812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 132912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 133212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 133312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 133412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 133512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 133612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 133712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onTimerRecordingResult(result); 133812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 1339e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onTimerRecordingResult.", e); 1340e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1341e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1342e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1343e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1344e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1345e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang void invokeClearTimerRecordingResult(int result) { 1346e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang synchronized (mLock) { 1347e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (mRecordListener != null) { 1348e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang try { 1349e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mRecordListener.onClearTimerRecordingResult(result); 1350e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } catch (RemoteException e) { 1351e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Failed to call onClearTimerRecordingResult.", e); 135212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 135612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 13577fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 13587fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 13597fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 13607fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 13617fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 13627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 13637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 136463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1365ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1366ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1367ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1368ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1369ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1370ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1371ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1372ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1373ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 13744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 13754893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 137660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 137760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 13784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 137960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 138260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 13834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 138460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 138560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 138660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 138760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 138860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 138960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1390e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1391e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 139279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 1393c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV); 139479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 139579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1396e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1397e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1398e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1399e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 140079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1401c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 1402c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK); 140360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1404a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1405a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1406a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1407a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 140892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 140992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 141092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 141192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 141292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 141392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 141438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 141538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 141638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 141738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 141838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 141938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1420c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1421c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 142238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 142438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1425c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1426c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 142738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 142938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1430c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 143138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 143238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 143338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 143438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 143538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1436fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo mWakeUpMessageReceived = true; 143738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 143838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 143938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 144038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 144138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 144238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 144338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 144438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 144538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 144638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 144738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 144838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 144938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 145038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 145138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 145238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 145338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 145438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 145538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1456c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 145738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1458a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1459fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo int startReason = INITIATED_BY_SCREEN_ON; 1460fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo if (mWakeUpMessageReceived) { 1461fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo startReason = INITIATED_BY_WAKE_UP_MESSAGE; 1462fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo } 1463fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(startReason); 1464a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 146538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 146638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 146738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 146838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 146938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 147038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 147138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 147238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 147338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1474c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 14754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 14774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 14784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 14794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 14804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 14814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 14824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 14834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 14844b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // We will not clear local devices here, since some OEM/SOC will keep passing 14854b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // the received packets until the application processor enters to the sleep 14864b54271f1bbd29957c47433155c58aa792105d6dYuncheol Heo // actually. 14874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 14904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 149338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 14944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 149538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 149638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 149738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 149838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 14994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 15004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 15024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 15034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 15054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 15064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 15094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 151038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 15114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 15124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1513c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 151438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 151538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1516c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 151738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 15184fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 151938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 152038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 1521c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.DISABLED); 152238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 15234d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1524119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1525119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1526119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1527119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1528119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1529119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1530119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1531119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1532119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1533119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1534119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1535119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1536119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1537119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1538119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1539119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1540119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1541119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1542119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1543119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1544119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1545119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1546119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1547119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1548119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1549119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1550119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1551119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1552119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 15534d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 15544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 15554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 15564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 15594d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 15604d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 15614d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 15624d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15634d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 15644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15654fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 15664fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void handleHdmiControlStatusChanged(boolean enabled) { 15674fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15684fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang int value = enabled ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED; 15704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, value); 15714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 15724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mMhlController.setOption(HdmiTvClient.OPTION_MHL_ENABLE, value); 15734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 15764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 15774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1580fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo initializeCec(INITIATED_BY_ENABLE_CEC); 15814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 15824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 15834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 15844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 15854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 15874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 15894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15910792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1592