HdmiControlService.java revision f4eb72d53b4c5bc2286841006ad473ad4448bcf8
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; 574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport com.android.server.hdmi.HdmiCecLocalDevice.PendingActionClearedCallback; 580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 59b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport libcore.util.EmptyArray; 60b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 6178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 62f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kimimport java.util.Arrays; 630340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 6402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 65a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 660792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 670792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 680792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 690792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 710792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 73c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim static final String PERMISSION = "android.permission.HDMI_CEC"; 7478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 75d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 76d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 77d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 78d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 79d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 82ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <ul> 844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_SUCCESS} 854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_NAK} 864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * <li>{@link Constants#SEND_RESULT_FAILURE} 874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * </ul> 88d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 89d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 90d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 91d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 9202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 9302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 9402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 9502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 9602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 9702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 9802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 9902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 10002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 10102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 10202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 10302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 10438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 10538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 10638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 10738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 10838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 10938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 11038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 11138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 11338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 11438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 11538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 11638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 11838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 12138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1260792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 12778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 12878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 12978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 13278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 13378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 13478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1354893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 13678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 13778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 13878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1394893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 14078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 14178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 14278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1436d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1446d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1454893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1466d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1476d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1486d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1494893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 153119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim // List of records for vendor command listener to handle the the caller killed in action. 154119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @GuardedBy("mLock") 155119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final ArrayList<VendorCommandListenerRecord> mVendorCommandListenerRecords = 156119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim new ArrayList<>(); 157119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1589c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1609c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1629c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1639c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 164b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 16512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private IHdmiRecordListener mRecordListener; 166b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 167b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @GuardedBy("mLock") 16812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private HdmiRecordListenerRecord mRecordListenerRecord; 169b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 17092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 17192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 17292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 17392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 17492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1764d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1774d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1784d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1794d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 1804d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 181ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 182ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 183ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 184ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 185ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 186ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 187ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 188ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1900340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1920792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1970792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 2000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 2010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2022b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from path(physical address) to port ID. 2032b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private SparseIntArray mPortIdMap = new SparseIntArray(); 2042b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 2052b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim // Map from port ID to HdmiPortInfo. 2062b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private SparseArray<HdmiPortInfo> mPortInfoMap = new SparseArray<>(); 2072b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 20875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo private HdmiCecMessageValidator mMessageValidator; 20975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo 21038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 21138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 21238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 213c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 21438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 21538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 21638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 21738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 2180792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 2190792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 2200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 2210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 2220792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2230792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 2240792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 2250792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 2262f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 227c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 2287ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mProhibitMode = false; 2297ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); 2308b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 231a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController = HdmiCecController.create(this); 2323ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 233347a60449981fc934e5a84122df87c1447665548Yuncheol Heo // TODO: Remove this as soon as OEM's HAL implementation is corrected. 234347a60449981fc934e5a84122df87c1447665548Yuncheol Heo mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, 235347a60449981fc934e5a84122df87c1447665548Yuncheol Heo HdmiTvClient.ENABLED); 236347a60449981fc934e5a84122df87c1447665548Yuncheol Heo 237a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang // TODO: load value for mHdmiControlEnabled from preference. 238a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 239a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang initializeCec(true); 240a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 241a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2420792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2430792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 245e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2460792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2470792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2480792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2492b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim initPortInfo(); 25075a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo mMessageValidator = new HdmiCecMessageValidator(this); 2518692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 25263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 25338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 25438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 25538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 25638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 25738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 25838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 25938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2607ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 26138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 2627ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim boolean readBooleanSetting(String key, boolean defVal) { 2637ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 2647ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim return Global.getInt(cr, key, defVal ? Constants.TRUE : Constants.FALSE) == Constants.TRUE; 2657ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim } 2667ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim 2677ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void writeBooleanSetting(String key, boolean value) { 2687ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim ContentResolver cr = getContext().getContentResolver(); 2697ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim Global.putInt(cr, key, value ? Constants.TRUE : Constants.FALSE); 2700792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 271e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 272a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang private void initializeCec(boolean fromBootup) { 273a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, 274a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang HdmiTvClient.ENABLED); 275a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang initializeLocalDevices(mLocalDevices, fromBootup); 276a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 277a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang 278a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 279a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang private void initializeLocalDevices(final List<Integer> deviceTypes, final boolean fromBootup) { 280a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2813ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 2823ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 2833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 28413c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim mCecController.clearLogicalAddress(); 2853ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 2863ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 2873ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 2883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 2893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 2903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 2913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 292c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (logicalAddress == Constants.ADDR_UNREGISTERED) { 2933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 2943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 2953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 2963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 2973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 2983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 2993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 3003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 3023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3034893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 3040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 305c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { 306c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_ON; 30738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 308a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang notifyAddressAllocated(devices, fromBootup); 3093ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3103ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 3123ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3133ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 315a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 316a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices, 317a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang boolean fromBootup) { 318a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3193ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 3203ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 3213ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 322a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang device.handleAddressAllocated(address, fromBootup); 3233ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3243ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 3270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 328a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3292b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim private void initPortInfo() { 330a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 3320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 3340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 3350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 3360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 3370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 3392b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return; 3402b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3412b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 3422b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 3432b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim mPortIdMap.put(info.getAddress(), info.getId()); 3442b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim mPortInfoMap.put(info.getId(), info); 3450340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3460340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 347f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mMhlController == null) { 348f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(Arrays.asList(cecPortInfo)); 349f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim return; 350f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 351f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim HdmiPortInfo[] mhlPortInfo = mMhlController.getPortInfos(); 352f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArraySet<Integer> mhlSupportedPorts = new ArraySet<Integer>(mhlPortInfo.length); 353f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : mhlPortInfo) { 354f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (info.isMhlSupported()) { 355f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mhlSupportedPorts.add(info.getId()); 356f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3570340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3580340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 359f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim // Build HDMI port info list with CEC port info plus MHL supported flag. 360f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 361f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim for (HdmiPortInfo info : cecPortInfo) { 362f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim if (mhlSupportedPorts.contains(info.getId())) { 363f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(new HdmiPortInfo(info.getId(), info.getType(), info.getAddress(), 364f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim info.isCecSupported(), true, info.isArcSupported())); 365f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } else { 366f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim result.add(info); 367f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim } 3682b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 369f4eb72d53b4c5bc2286841006ad473ad4448bcf8Jinsuk Kim mPortInfo = Collections.unmodifiableList(result); 3702b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3710340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3720340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3730340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 3740340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 3750340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 3760340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 3770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 3780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 3792b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 3800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 3812b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 3822b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId, null); 3830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 385e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 386401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 387401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 388401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 3892b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 390401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 3912b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 392401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 393401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 394401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 395c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return Constants.INVALID_PHYSICAL_ADDRESS; 396401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 397401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 398401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 399401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 400401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 401401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 402401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 403401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 404401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 405401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 4062b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 407401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 4082b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 409c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int portAddress = path & Constants.ROUTING_PATH_TOP_MASK; 4102b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortIdMap.get(portAddress, Constants.INVALID_PORT_ID); 411401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 412401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 4132b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 41409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim boolean isValidPortId(int portId) { 4152b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 4162b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return getPortInfo(portId) != null; 41709ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 41809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim 419401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 420e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 421e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 422e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 423e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 424e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 425e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 426e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 427e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 428e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 429e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 430e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 431e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 432e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 433e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 434e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 43567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 436e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 437c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 438c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 4393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 4403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 4423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 4433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 4453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 4463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 4473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 4483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 4493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 4503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 452a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 453a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 4540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 45579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 45679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 45779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 45879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 45979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 460a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 461a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 4623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 463092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 464092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 465092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 466092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 467092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 468092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 469092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 47060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 47160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 4722b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim @ServiceThreadOnly 47360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 4742b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim assertRunOnServiceThread(); 4752b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int portId = mPortIdMap.get(physicalAddress); 4762b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 4772b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mPortInfoMap.get(portId).isArcSupported(); 47860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 47960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 48060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 48160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 48279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 48367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 48467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 48567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 48663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 48763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 48863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 48963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 49063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 49163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 49263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 49363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 49463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 49563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 49667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 497c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 498c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 499c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 500d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 501c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 502a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 503d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 504a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 505d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 506d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 507d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 508a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 509d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 510a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 511d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 512c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 513c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 514a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 515a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 516a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 51775a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo if (!mMessageValidator.isValid(message)) { 51875a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo return false; 51975a77e7d6cbfc287c6126efd28b338b48b7ea70cYuncheol Heo } 520092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 521092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 522092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 52379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 52479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 52560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 52660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 527a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 528092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 529a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 530092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 53179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 532c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim && message.getDestination() != Constants.ADDR_BROADCAST) { 533092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 534092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 535092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 53660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 537c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (message.getDestination() != Constants.ADDR_BROADCAST) { 5383a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 5393a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 540092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 541a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 542a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 54367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 54467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 54567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 5468b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 54767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 54867ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 549a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 55067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 55160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 55279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 55379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 55460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 55560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 55667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 55767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 55802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 55902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 56002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 56102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 56202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 5631de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 5640f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 56502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 5660f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 56702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 568a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5691de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 5701de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 571a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5721de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 5731de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 5740f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5750f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 5760f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 577c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int strategy = pickStrategy & Constants.POLL_STRATEGY_MASK; 5780f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 5790f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 5800f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 581c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim int iterationStrategy = pickStrategy & Constants.POLL_ITERATION_STRATEGY_MASK; 5820f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 5830f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 5840f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5850f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 58602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 58702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 58960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 59060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 59160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 59260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 59379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 59479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 59579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 59679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 59779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 598b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager audioManager = getAudioManager(); 599b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang boolean muted = audioManager.isStreamMute(AudioManager.STREAM_MUSIC); 600b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (mute) { 601b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (!muted) { 602b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, true); 603b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 604b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } else { 605b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang if (muted) { 606b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamMute(AudioManager.STREAM_MUSIC, false); 607b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 608b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing 609b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang // volume change notification back to hdmi control service. 610b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 611b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_SHOW_UI | 612b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME); 613b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang } 6143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6153ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 616ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 617ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 618ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 619ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 620ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 621ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 6223ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 62342c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 62442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 6253ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 6262b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getPhysicalAddress(), pathToPortId(getPhysicalAddress()), deviceType, 6272b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim getVendorId(), displayName); 6283ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 6293ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 63078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 63178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 63278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 63378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 63478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 63578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 63678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 63778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 63878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 63978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 64078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 64178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 64278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 64378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 64478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 64778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 6486d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 6496d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 6506d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6516d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 6526d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 6536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6546d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 6556d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 656ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 6576d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 6586d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 6596d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 6606d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6616d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6626d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 6636d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 664ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 66538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 666ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 667ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 668ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 669ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 670ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 671ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 672ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 673ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 674ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 675ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 676ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 677ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 678ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 679ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 680119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim class VendorCommandListenerRecord implements IBinder.DeathRecipient { 681119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final IHdmiVendorCommandListener mListener; 682119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private final int mDeviceType; 683119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 684119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public VendorCommandListenerRecord(IHdmiVendorCommandListener listener, int deviceType) { 685119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mListener = listener; 686119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mDeviceType = deviceType; 687119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 688119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 689119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 690119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void binderDied() { 691119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 692119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.remove(this); 693119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 694119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 695119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 696119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 69712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private class HdmiRecordListenerRecord implements IBinder.DeathRecipient { 698b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 699b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void binderDied() { 700b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 70112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = null; 702b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 703b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 704b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 705b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 70678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 70778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 70878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 70978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 71078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 71178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 71278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 71378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 7150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 7160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 7170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 71878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 72078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 72178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 72278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 723a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 724a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 725a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 726a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 727a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 72879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 729a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 730a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 731c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 732a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 733a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 734a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 735a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 736a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 737a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 738a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 739a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 740a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 741a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 742a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 743a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 744a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 745a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 746a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 747a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 748c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 749a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 750a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 7518333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 752a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 753a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 754a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 755a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 756a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 757c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim public void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) { 758a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 759a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 760a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 761a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 762c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType); 763c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim if (localDevice == null) { 764c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "Local device not available"); 765a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 766a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 767c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim localDevice.sendKeyEvent(keyCode, isPressed); 768a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 769a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 770a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 771a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 772a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 7737fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 77478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7757fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7767fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7777fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7787fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 7797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7807fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 78178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 78278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 78378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 78578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 7907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7917fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 79278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 79378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 79478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 79678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8007fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 8017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 80378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 80478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 80578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 8067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 80778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 8087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 8097fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 8107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 8117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 8127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 8137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 81478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 8156d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8166d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8176d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 8186d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8196d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 8206d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 821ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 8226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 8236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8246d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 8256d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 8266d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 8276d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 8286d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 8296d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 8306d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 8316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 832ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 833ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 834ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 835ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 836ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 837ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 838ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 839ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 840e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 841ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 842ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 843ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 844ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 845ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 846ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 847ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 848ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 849ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 850377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return tv.isSystemAudioActivated(); 851ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 852ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 853ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 854ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 855ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 856ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 857ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 858ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 859ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 860ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 861ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 862c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 863ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 864ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 865ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 866ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 867ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 868ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 869ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 870ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 871ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 872ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 873ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 874ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 875ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 876ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 877ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 878ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 879ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 880ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 881ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 882ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 88392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 88492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 8859c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 8869c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 8879c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 8889c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8899c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 8909c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 8919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public List<HdmiCecDeviceInfo> getInputDevices() { 8929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 8939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 8949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 8959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 8969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 8979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 8989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 9009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 9019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 9029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 903160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setControlEnabled(final boolean enabled) { 90492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim enforceAccessPermission(); 90592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim runOnServiceThread(new Runnable() { 90692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 90792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim public void run() { 9084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang handleHdmiControlStatusChanged(enabled); 9094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 91092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 91192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim }); 91292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 913a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 914a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 91541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 91641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 91741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 91841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 91941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 92041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 92141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 92241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 92341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 92441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 92541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 92641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 92741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 92841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 92941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 93041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 93141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 93241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 93341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 93441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 93541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 93641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 93741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 93841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 93941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 94041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 94141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 94241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 94341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 94441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 94541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 94641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 94741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 948a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 949a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 950a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 951a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 952a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 953a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 954a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 95538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 956a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 957a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 958a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 959a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 960a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 961160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 962160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 963160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setOption(final int key, final int value) { 9644d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 965160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (!isTvDevice()) { 966160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return; 967160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 968160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim switch (key) { 969c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_WAKEUP: 970160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(key, value); 971160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 972c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_CEC_AUTO_DEVICE_OFF: 973160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // No need to pass this option to HAL. 974c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim tv().setAutoDeviceOff(value == HdmiTvClient.ENABLED); 975160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 976c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_INPUT_SWITCHING: // Fall through 977c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case HdmiTvClient.OPTION_MHL_POWER_CHARGE: 978160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 979160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(key, value); 980160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 981160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 982160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 983160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 984160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 9854d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @Override 9864d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 9874d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 9884d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 9894d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 9904d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 9914d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 9924d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 993119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 994119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 995119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void addVendorCommandListener(final IHdmiVendorCommandListener listener, 996119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final int deviceType) { 997119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 998119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 999119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1000119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1001119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiControlService.this.addVendorCommandListener(listener, deviceType); 1002119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1003119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 1004119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1005119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1006119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1007119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void sendVendorCommand(final int deviceType, final int targetAddress, 1008119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim final byte[] params, final boolean hasVendorId) { 1009119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim enforceAccessPermission(); 1010119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim runOnServiceThread(new Runnable() { 1011119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim @Override 1012119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim public void run() { 1013119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim HdmiCecLocalDevice device = mCecController.getLocalDevice(deviceType); 1014119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (device == null) { 1015119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Local device not available"); 1016119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1017119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1018119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (hasVendorId) { 1019119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommandWithId( 1020119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, 1021119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim getVendorId(), params)); 1022119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 1023119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim sendCecCommand(HdmiCecMessageBuilder.buildVendorCommand( 1024119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim device.getDeviceInfo().getLogicalAddress(), targetAddress, params)); 1025119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1026119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1027119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim }); 102812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1029a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1030a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 103112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang public void setHdmiRecordListener(IHdmiRecordListener listener) { 103212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlService.this.setHdmiRecordListener(listener); 1033b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1034b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1035b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1036b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { 1037b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1038b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1039b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1040b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1041b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1042b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1043b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1044b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startOneTouchRecord(recorderAddress, recordSource); 1045b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1046b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1047b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1048b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1049b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1050b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void stopOneTouchRecord(final int recorderAddress) { 1051b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1052b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1053b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1054b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1055b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1056b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1057b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1058b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().stopOneTouchRecord(recorderAddress); 1059b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1060b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1061a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 1062a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang 1063a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang @Override 1064b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void startTimerRecording(final int recorderAddress, final int sourceType, 1065b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1066b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1067b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1068b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1069b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1070b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1071b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1072b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1073b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().startTimerRecording(recorderAddress, sourceType, recordSource); 1074b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1075b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1076bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang } 1077bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang 1078bffb0635aaaaf9140d9120e3f3d95a4f7391a0acJungshik Jang @Override 1079b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void clearTimerRecording(final int recorderAddress, final int sourceType, 1080b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang final byte[] recordSource) { 1081b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang runOnServiceThread(new Runnable() { 1082b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1083b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang public void run() { 1084b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!isTvDevice()) { 1085b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "No TV is available."); 1086b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1087b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1088b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang tv().clearTimerRecording(recorderAddress, sourceType, recordSource); 1089b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1090b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang }); 1091a6b2a7a59ab79b2d91412c1095d1c49b8dc9d507Jungshik Jang } 109278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 109378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1094a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 109579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 109679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 109779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 10987fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 10997fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1100c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11027fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 110379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 110478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 110578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1106a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 110779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 110879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 110979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 11107fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 11117fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 1112c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SOURCE_NOT_AVAILABLE); 11137fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 11147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 111579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 111678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 111778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 111878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 111978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 112078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 112178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 112278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 112378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 112478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 112578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 112678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 112778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 112878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 112978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 113178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 113278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 113378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 113478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 113578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 113678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 113778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 113878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 113978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 114078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 114178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 114278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 114378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 11447fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 11456d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 11464893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 11474893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 11484893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 11494893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 11504893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 11514893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 11524893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 11536d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 11544893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 11554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 11564893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 11574893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 11584893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 11594893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 11604893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 11614893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 11624893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 11634893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 11644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 11654893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 11666d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11676d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11686d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11696d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 11706d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1171ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 1172ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1173ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1174ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1175ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1176ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1177ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1178ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1179ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1180ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1181ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1182ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1183ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1184ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1185ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1186ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1187ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1188ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1189ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1190ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1191ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1192ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1193ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1194ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1195ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1196ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1197ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1198ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1199ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 12009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 12019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 12029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 12039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 12059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 12109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 12129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 12139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 12149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12159c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 12169c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 12179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12189c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 12199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 12229c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim void invokeInputChangeListener(int activeAddress) { 12239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 12249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 12259c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress); 12269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 12279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener.onChanged(activeSource); 12289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 12299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 12309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 12349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 123512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private void setHdmiRecordListener(IHdmiRecordListener listener) { 1236b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 123712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListenerRecord = new HdmiRecordListenerRecord(); 1238b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang try { 123912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang listener.asBinder().linkToDeath(mRecordListenerRecord, 0); 1240b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } catch (RemoteException e) { 124112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Listener already died.", e); 1242b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 124312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener = listener; 1244b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1245b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1246b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1247b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] invokeRecordRequestListener(int recorderAddress) { 1248b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang synchronized (mLock) { 124912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 125012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 125112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return mRecordListener.getOneTouchRecordSource(recorderAddress); 125212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 125312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to start record.", e); 1254b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1255b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1256b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return EmptyArray.BYTE; 1257b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1258b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1259b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 126012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeOneTouchRecordResult(int result) { 126112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 126212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 126312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 126412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onOneTouchRecordResult(result); 126512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 126612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 126712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 126812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 126912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 127012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 127112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 127212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang void invokeTimerRecordingResult(int result) { 127312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang synchronized (mLock) { 127412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (mRecordListener != null) { 127512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang try { 127612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang mRecordListener.onTimerRecordingResult(result); 127712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } catch (RemoteException e) { 127812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Failed to call onOneTouchRecordResult.", e); 127912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 128012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 128112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 128212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 128312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 12847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 12857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 12867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 12877fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 12887fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 12897fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 12907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 129163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1292ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1293ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1294ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1295ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1296ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1297ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1298ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1299ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1300ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 13014893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 13024893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 130360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 130460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 13054893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 130660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 130760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 130860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 130960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 13104893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 131160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 131260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 131360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 131460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 131560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 131660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1317e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1318e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 131960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 1320c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (path1 & Constants.ROUTING_PATH_TOP_MASK) 1321c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim == (path2 & Constants.ROUTING_PATH_TOP_MASK); 132260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 132360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 132479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 1325c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_TV); 132679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 132779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1328e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo boolean isTvDevice() { 1329e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo return tv() != null; 1330e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo } 1331e946ed8f54c5ee0e58e168df00d4f418e1eed7a7Yuncheol Heo 133279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 1333c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return (HdmiCecLocalDevicePlayback) 1334c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.getLocalDevice(HdmiCecDeviceInfo.DEVICE_PLAYBACK); 133560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1336a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1337a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1338a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1339a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 134092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 134192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 134292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 134392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 134492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 134592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 134638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 134738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 134838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 134938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 135038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 135138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 1352c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_ON 1353c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 135438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 135538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 135638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 1357c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY 1358c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim || mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 135938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 136038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 136138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 1362c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return mPowerStatus == HdmiControlManager.POWER_STATUS_STANDBY; 136338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 136438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 136538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 136638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 136738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 136838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 136938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 137038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 137138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 137238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 137338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 137438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 137538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 137638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 137738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 137838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 137938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 138038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 138138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 138238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 138338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 138438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 138538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 138638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1387c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; 138838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 1389a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang if (mHdmiControlEnabled) { 1390a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang initializeCec(true); 1391a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang } 139238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 139338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 139438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 139538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 139638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 139738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 139838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 139938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 140038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 1401c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; 14024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); 14044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 14054fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 14064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 14074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "On standby-action cleared:" + device.mDeviceType); 14084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang devices.remove(device); 14094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (devices.isEmpty()) { 14104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 14114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang onStandbyCompleted(); 14124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 14154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14164fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14174fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableDevices(PendingActionClearedCallback callback) { 141838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 14194fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.disableDevice(mStandbyMessageReceived, callback); 142038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 142238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 142338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 14244fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void clearLocalDevices() { 14254fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 14264fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mCecController == null) { 14274fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 14284fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14294fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLogicalAddress(); 14304fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.clearLocalDevices(); 14314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 14344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void onStandbyCompleted() { 143538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 14364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang Slog.v(TAG, "onStandbyCompleted"); 14374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1438c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (mPowerStatus != HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY) { 143938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 144038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1441c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPowerStatus = HdmiControlManager.POWER_STATUS_STANDBY; 144238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 14434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang device.onStandby(mStandbyMessageReceived); 144438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 144538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 1446c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mCecController.setOption(HdmiTvClient.OPTION_CEC_SERVICE_CONTROL, HdmiTvClient.DISABLED); 144738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 14484d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 1449119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim private void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType) { 1450119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim VendorCommandListenerRecord record = new VendorCommandListenerRecord(listener, deviceType); 1451119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1452119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim listener.asBinder().linkToDeath(record, 0); 1453119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1454119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.w(TAG, "Listener already died"); 1455119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return; 1456119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1457119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1458119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mVendorCommandListenerRecords.add(record); 1459119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1460119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1461119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 1462119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim void invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, 1463119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim boolean hasVendorId) { 1464119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim synchronized (mLock) { 1465119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { 1466119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (record.mDeviceType != deviceType) { 1467119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim continue; 1468119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1469119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim try { 1470119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim record.mListener.onReceived(srcAddress, params, hasVendorId); 1471119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } catch (RemoteException e) { 1472119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.e(TAG, "Failed to notify vendor command reception", e); 1473119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1474119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1475119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1476119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 1477119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 14784d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 14794d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 14804d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 14814d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 14824d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 14834d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 14844d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 14854d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 14864d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 14874d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 14884d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 14894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 14914fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void handleHdmiControlStatusChanged(boolean enabled) { 14924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 14934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 14944fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang int value = enabled ? HdmiTvClient.ENABLED : HdmiTvClient.DISABLED; 14954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mCecController.setOption(HdmiTvClient.OPTION_CEC_ENABLE, value); 14964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mMhlController != null) { 14974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mMhlController.setOption(HdmiTvClient.OPTION_MHL_ENABLE, value); 14984fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 14994fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15004fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang synchronized (mLock) { 15014fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHdmiControlEnabled = enabled; 15024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15034fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 15044fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (enabled) { 1505a9f10629f4bc1a82761917645ff4d2b6d42e47b3Jungshik Jang initializeCec(false); 15064fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } else { 15074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableDevices(new PendingActionClearedCallback() { 15084fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 15094fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void onCleared(HdmiCecLocalDevice device) { 15104fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 15114fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang clearLocalDevices(); 15124fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15134fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }); 15144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15154fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 15160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1517