HdmiControlService.java revision 5344cd98e69f92e70d52969b1851c9d8f9e81853
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; 210792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.content.Context; 2238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.Intent; 2338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.content.IntentFilter; 24a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jangimport android.hardware.hdmi.HdmiCec; 25c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecDeviceInfo; 26c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kimimport android.hardware.hdmi.HdmiCecMessage; 2760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.HdmiHotplugEvent; 280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 29d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 30d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiControlService; 316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kimimport android.hardware.hdmi.IHdmiDeviceEventListener; 32d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jangimport android.hardware.hdmi.IHdmiHotplugEventListener; 339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kimimport android.hardware.hdmi.IHdmiInputChangeListener; 34ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jangimport android.hardware.hdmi.IHdmiSystemAudioModeChangeListener; 35a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioManager; 3642c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jangimport android.os.Build; 3767ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jangimport android.os.Handler; 380792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.os.HandlerThread; 3978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.IBinder; 40e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jangimport android.os.Looper; 4138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.PowerManager; 4278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport android.os.RemoteException; 4338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heoimport android.os.SystemClock; 440792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport android.util.Slog; 453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport android.util.SparseArray; 468b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jangimport android.util.SparseIntArray; 4778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 484893c7efde52411ad051ef5c20251439f4098eacJinsuk Kimimport com.android.internal.annotations.GuardedBy; 490792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangimport com.android.server.SystemService; 50a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jangimport com.android.server.hdmi.HdmiCecController.AllocateAddressCallback; 520792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 5378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kimimport java.util.ArrayList; 540340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kimimport java.util.Collections; 5502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jangimport java.util.List; 56a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 570792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang/** 580792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * Provides a service for sending and processing HDMI control messages, 590792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang * HDMI-CEC and MHL control command, and providing the information on both standard. 600792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang */ 610792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jangpublic final class HdmiControlService extends SystemService { 620792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private static final String TAG = "HdmiControlService"; 630792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 6478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // TODO: Rename the permission to HDMI_CONTROL. 6578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private static final String PERMISSION = "android.permission.HDMI_CEC"; 6678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 67d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 68d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Interface to report send result. 69d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 70d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang interface SendMessageCallback { 71d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang /** 72d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * Called when {@link HdmiControlService#sendCecCommand} is completed. 73d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * 74ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @param error result of send request. 75ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_SUCCESS} 76ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_NAK} 77ece603b7955938d6001c376f351ca0a2219330acYuncheol Heo * @see {@link #SEND_RESULT_FAILURE} 78d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang */ 79d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void onSendCompleted(int error); 80d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 81d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 8202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Interface to get a list of available logical devices. 8402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 8502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang interface DevicePollingCallback { 8602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 8702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Called when device polling is finished. 8802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 8902bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param ackedAddress a list of logical addresses of available devices 9002bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 9102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang void onPollingFinished(List<Integer> ackedAddress); 9202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 9302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 9438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private class PowerStateReceiver extends BroadcastReceiver { 9538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 9638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo public void onReceive(Context context, Intent intent) { 9738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo switch (intent.getAction()) { 9838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_OFF: 9938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerOnOrTransient()) { 10038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onStandby(); 10138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 10238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 10338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo case Intent.ACTION_SCREEN_ON: 10438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (isPowerStandbyOrTransient()) { 10538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo onWakeUp(); 10638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 10738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo break; 10838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 10938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1120792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // A thread to handle synchronous IO of CEC and MHL control service. 1130792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) 1140792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang // and sparse call it shares a thread to handle IO operations. 1150792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); 1160792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 11778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Used to synchronize the access to the service. 11878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final Object mLock = new Object(); 11978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Type of logical devices hosted in the system. Stored in the unmodifiable list. 1210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final List<Integer> mLocalDevices; 12278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 12378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of listeners registered by callers that want to get notified of 12478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // hotplug events. 1254893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 12678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<IHdmiHotplugEventListener> mHotplugEventListeners = new ArrayList<>(); 12778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 12878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // List of records for hotplug event listener to handle the the caller killed in action. 1294893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 13078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords = 13178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim new ArrayList<>(); 13278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 1336d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of listeners registered by callers that want to get notified of 1346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // device status events. 1354893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<IHdmiDeviceEventListener> mDeviceEventListeners = new ArrayList<>(); 1376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1386d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim // List of records for device event listener to handle the the caller killed in action. 1394893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim @GuardedBy("mLock") 1406d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final ArrayList<DeviceEventListenerRecord> mDeviceEventListenerRecords = 1416d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim new ArrayList<>(); 1426d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 1439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private IHdmiInputChangeListener mInputChangeListener; 1459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 1469c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @GuardedBy("mLock") 1479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private InputChangeListenerRecord mInputChangeListenerRecord; 1489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 14992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Set to true while HDMI control is enabled. If set to false, HDMI-CEC/MHL protocol 15092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // handling will be disabled and no request will be handled. 15192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @GuardedBy("mLock") 15292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim private boolean mHdmiControlEnabled; 15392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 1544d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // Set to true while the service is in normal mode. While set to false, no input change is 1554d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // allowed. Used for situations where input change can confuse users such as channel auto-scan, 1564d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // system upgrade, etc., a.k.a. "prohibit mode". 1574d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @GuardedBy("mLock") 1584d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim private boolean mProhibitMode; 1594d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 160ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of listeners registered by callers that want to get notified of 161ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // system audio mode changes. 162ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<IHdmiSystemAudioModeChangeListener> 163ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners = new ArrayList<>(); 164ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang // List of records for system audio mode change to handle the the caller killed in action. 165ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final ArrayList<SystemAudioModeChangeListenerRecord> 166ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords = new ArrayList<>(); 167ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1684893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Handler used to run a task in service thread. 1690340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private final Handler mHandler = new Handler(); 1700340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 1710792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1720792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiCecController mCecController; 1730792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1740792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Nullable 1750792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang private HdmiMhlController mMhlController; 1760792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // HDMI port information. Stored in the unmodifiable list to keep the static information 1780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // from being modified. 1790340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> mPortInfo; 1800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 18138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final PowerStateReceiver mPowerStateReceiver = new PowerStateReceiver(); 18238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 18338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 18438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private int mPowerStatus = HdmiCec.POWER_STATUS_STANDBY; 18538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 18638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 18738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private boolean mStandbyMessageReceived = false; 18838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 1890792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public HdmiControlService(Context context) { 1900792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang super(context); 1910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mLocalDevices = HdmiUtils.asImmutableList(getContext().getResources().getIntArray( 1920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim com.android.internal.R.array.config_hdmiCecLogicalDeviceType)); 1930792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 1940792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 1950792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang @Override 1960792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang public void onStart() { 1972f51aec689226e259d08bf04d838251f249572e3Jungshik Jang mIoThread.start(); 19838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mPowerStatus = HdmiCec.POWER_STATUS_TRANSIENT_TO_ON; 199e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mCecController = HdmiCecController.create(this); 2008b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 2013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (mCecController != null) { 20238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mCecController.setOption(HdmiCec.OPTION_CEC_SERVICE_CONTROL, HdmiCec.DISABLED); 2033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang initializeLocalDevices(mLocalDevices); 204a8a5e50c6f9ba3ae0ff59eda76354e93515d6f8fJinsuk Kim } else { 2050792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support HDMI-CEC."); 2060792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2070792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang 208e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang mMhlController = HdmiMhlController.create(this); 2090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang if (mMhlController == null) { 2100792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang Slog.i(TAG, "Device does not support MHL-control."); 2110792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 2120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mPortInfo = initPortInfo(); 2138692fc68a413c7aca75f094bb02bcbabcc277c73Jinsuk Kim publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); 21463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 21538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Register broadcast receiver for power state change. 21638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null || mMhlController != null) { 21738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo IntentFilter filter = new IntentFilter(); 21838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_OFF); 21938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo filter.addAction(Intent.ACTION_SCREEN_ON); 22038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo getContext().registerReceiver(mPowerStateReceiver, filter); 22138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 22238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 22363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // TODO: Read the preference for SystemAudioMode and initialize mSystemAudioMode and 22463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo // start to monitor the preference value and invoke SystemAudioActionFromTv if needed. 22592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim mHdmiControlEnabled = true; 2264d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim // TODO: Get control flag from persistent storage 2274d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = false; 2280792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang } 229e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 230a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private void initializeLocalDevices(final List<Integer> deviceTypes) { 232a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2333ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang // A container for [Logical Address, Local device info]. 2343ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseArray<HdmiCecLocalDevice> devices = new SparseArray<>(); 2353ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final SparseIntArray finished = new SparseIntArray(); 23613c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim mCecController.clearLogicalAddress(); 2373ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int type : deviceTypes) { 2383ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang final HdmiCecLocalDevice localDevice = HdmiCecLocalDevice.create(this, type); 2393ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.init(); 2403ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.allocateLogicalAddress(type, 2413ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.getPreferredAddress(), new AllocateAddressCallback() { 2423ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang @Override 2433ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang public void onAllocated(int deviceType, int logicalAddress) { 2443ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang if (logicalAddress == HdmiCec.ADDR_UNREGISTERED) { 2453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang Slog.e(TAG, "Failed to allocate address:[device_type:" + deviceType + "]"); 2463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } else { 2473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecDeviceInfo deviceInfo = createDeviceInfo(logicalAddress, deviceType); 2483ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang localDevice.setDeviceInfo(deviceInfo); 2493ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLocalDevice(deviceType, localDevice); 2503ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mCecController.addLogicalAddress(logicalAddress); 2513ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang devices.append(logicalAddress, localDevice); 2523ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang finished.append(deviceType, logicalAddress); 2543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2554893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim // Address allocation completed for all devices. Notify each device. 2560340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (deviceTypes.size() == finished.size()) { 25738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mPowerStatus == HdmiCec.POWER_STATUS_TRANSIENT_TO_ON) { 25838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mPowerStatus = HdmiCec.POWER_STATUS_ON; 25938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 2603ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang notifyAddressAllocated(devices); 2613ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2633ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang }); 2643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2663ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 267a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2683ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private void notifyAddressAllocated(SparseArray<HdmiCecLocalDevice> devices) { 269a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2703ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang for (int i = 0; i < devices.size(); ++i) { 2713ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int address = devices.keyAt(i); 2723ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDevice device = devices.valueAt(i); 27313c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim device.handleAddressAllocated(address); 2743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2753ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 2763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 2770340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Initialize HDMI port information. Combine the information from CEC and MHL HAL and 2780340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // keep them in one place. 279a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2800340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim private List<HdmiPortInfo> initPortInfo() { 281a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 2820340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] cecPortInfo = null; 2830340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2840340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // CEC HAL provides majority of the info while MHL does only MHL support flag for 2850340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // each port. Return empty array if CEC HAL didn't provide the info. 2860340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mCecController != null) { 2870340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cecPortInfo = mCecController.getPortInfos(); 2880340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2890340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (cecPortInfo == null) { 2900340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.emptyList(); 2910340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2920340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2930340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo[] mhlPortInfo = new HdmiPortInfo[0]; 2940340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (mMhlController != null) { 2950340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // TODO: Implement plumbing logic to get MHL port information. 2960340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mhlPortInfo = mMhlController.getPortInfos(); 2970340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 2980340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 2990340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // Use the id (port number) to find the matched info between CEC and MHL to combine them 3000340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // into one. Leave the field `mhlSupported` to false if matched MHL entry is not found. 3010340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim ArrayList<HdmiPortInfo> result = new ArrayList<>(cecPortInfo.length); 3020340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < cecPortInfo.length; ++i) { 3030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo cec = cecPortInfo[i]; 3040340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int id = cec.getId(); 3050340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim boolean mhlInfoFound = false; 3060340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo mhl : mhlPortInfo) { 3070340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (id == mhl.getId()) { 3080340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(new HdmiPortInfo(id, cec.getType(), cec.getAddress(), 3090340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim cec.isCecSupported(), mhl.isMhlSupported(), cec.isArcSupported())); 3100340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim mhlInfoFound = true; 3110340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim break; 3120340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3130340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3140340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (!mhlInfoFound) { 3150340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim result.add(cec); 3160340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3170340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return Collections.unmodifiableList(result); 3200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 3220340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim /** 3230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * Returns HDMI port information for the given port id. 3240340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * 3250340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @param portId HDMI port id 3260340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim * @return {@link HdmiPortInfo} for the given port 3270340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim */ 3280340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim HdmiPortInfo getPortInfo(int portId) { 3290340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mPortInfo is an unmodifiable list and the only reference to its inner list. 3300340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // No lock is necessary. 3310340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 3320340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim if (portId == info.getId()) { 3330340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return info; 3340340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3350340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3360340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return null; 3370340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim } 3380340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim 339e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 340401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the routing path (physical address) of the HDMI port for the given 341401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * port id. 342401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 343401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portIdToPath(int portId) { 344401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim HdmiPortInfo portInfo = getPortInfo(portId); 345401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portInfo == null) { 346401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim Slog.e(TAG, "Cannot find the port info: " + portId); 34760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PHYSICAL_ADDRESS; 348401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 349401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return portInfo.getAddress(); 350401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 351401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 352401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 353401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * Returns the id of HDMI port located at the top of the hierarchy of 354401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the specified routing path. For the routing path 0x1220 (1.2.2.0), for instance, 355401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * the port id to be returned is the ID associated with the port address 356401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim * 0x1000 (1.0.0.0) which is the topmost path of the given routing path. 357401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim */ 358401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int pathToPortId(int path) { 359401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim int portAddress = path & HdmiConstants.ROUTING_PATH_TOP_MASK; 360401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim for (HdmiPortInfo info : mPortInfo) { 361401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim if (portAddress == info.getAddress()) { 362401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim return info.getId(); 363401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 364401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 36560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return HdmiConstants.INVALID_PORT_ID; 366401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim } 367401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim 368401e3de791c0e2a4348361fbd560da9530156e22Jinsuk Kim /** 369e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} for IO operation. 370e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 371e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 372e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 373e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getIoLooper() { 374e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang return mIoThread.getLooper(); 375e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 376e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang 377e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang /** 378e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * Returns {@link Looper} of main thread. Use this {@link Looper} instance 379e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * for tasks that are running on main service thread. 380e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * 381e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang * <p>Declared as package-private. 382e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang */ 383e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang Looper getServiceLooper() { 38467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang return mHandler.getLooper(); 385e9c77c88ea34a66f83a94f960547275c0ff6bd07Jungshik Jang } 386c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 387c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim /** 3883ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns physical address of the device. 3893ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3903ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getPhysicalAddress() { 3913ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getPhysicalAddress(); 3923ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 3933ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 3943ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 3953ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Returns vendor id of CEC service. 3963ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang */ 3973ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang int getVendorId() { 3983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return mCecController.getVendorId(); 3993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 4003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 401a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 402a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim HdmiCecDeviceInfo getDeviceInfo(int logicalAddress) { 4030340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim assertRunOnServiceThread(); 40479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 40579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (tv == null) { 40679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 40779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 40879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return tv.getDeviceInfo(logicalAddress); 409a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 410a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 4113ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang /** 412092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Returns version of CEC. 413092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 414092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int getCecVersion() { 415092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return mCecController.getVersion(); 416092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 417092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 418092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 41960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang * Whether a device of the specified physical address is connected to ARC enabled port. 42060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang */ 42160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang boolean isConnectedToArcPort(int physicalAddress) { 42260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiPortInfo portInfo : mPortInfo) { 42360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang if (hasSameTopPort(portInfo.getAddress(), physicalAddress) 42460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang && portInfo.isArcSupported()) { 42560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return true; 42660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 42760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 42860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 42960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 43060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 43179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void runOnServiceThread(Runnable runnable) { 43267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang mHandler.post(runnable); 43367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 43467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 43563a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo void runOnServiceThreadAtFrontOfQueue(Runnable runnable) { 43663a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo mHandler.postAtFrontOfQueue(runnable); 43763a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 43863a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 43963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo private void assertRunOnServiceThread() { 44063a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo if (Looper.myLooper() != mHandler.getLooper()) { 44163a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo throw new IllegalStateException("Should run on service thread."); 44263a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 44363a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo } 44463a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 44567ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 446c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * Transmit a CEC command to CEC bus. 447c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * 448c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim * @param command CEC command to send out 449d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang * @param callback interface used to the result of send command 450c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim */ 451a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 452d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { 453a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 454d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, callback); 455d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang } 456d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang 457a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 458d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang void sendCecCommand(HdmiCecMessage command) { 459a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 460d643f764f72efc1e7aa67392bf9ac40720ae14c3Jungshik Jang mCecController.sendCommand(command, null); 461c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim } 462c70d2295dd3fb87ce8c81c704688d1ad05043b4dJinsuk Kim 463a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 464a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang boolean handleCecCommand(HdmiCecMessage message) { 465a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 466092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return dispatchMessageToLocalDevice(message); 467092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 468092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 46979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioReturnChannel(boolean enabled) { 47079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecController.setAudioReturnChannel(enabled); 47160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 47260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 473a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 474092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private boolean dispatchMessageToLocalDevice(HdmiCecMessage message) { 475a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 476092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 47779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device.dispatchMessage(message) 47879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang && message.getDestination() != HdmiCec.ADDR_BROADCAST) { 479092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 480092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 481092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 48260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 4833a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang if (message.getDestination() != HdmiCec.ADDR_BROADCAST) { 4843a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang Slog.w(TAG, "Unhandled cec command:" + message); 4853a959fca91bce393cc1ee79aa2985bb06542016eJungshik Jang } 486092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 487a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang } 488a1fa91fe263c483cf13066e2847a440de2cd52a5Jungshik Jang 48967ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang /** 49067ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * Called when a new hotplug event is issued. 49167ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * 4928b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang * @param portNo hdmi port number where hot plug event issued. 49367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang * @param connected whether to be plugged in or not 49467ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang */ 495a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 49667ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang void onHotplug(int portNo, boolean connected) { 49760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 49879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 49979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang device.onHotplug(portNo, connected); 50060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 50160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang announceHotplugEvent(portNo, connected); 50267ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang } 50367ea521d14f366fe5aac09e512865d31bfa0ee53Jungshik Jang 50402bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang /** 50502bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * Poll all remote devices. It sends <Polling Message> to all remote 50602bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * devices. 50702bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * 50802bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param callback an interface used to get a list of all remote devices' address 5091de514256fd3015cf45256f3198ab5472024af9bJungshik Jang * @param sourceAddress a logical address of source device where sends polling message 5100f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @param pickStrategy strategy how to pick polling candidates 51102bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang * @param retryCount the number of retry used to send polling message to remote devices 5120f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang * @throw IllegalArgumentException if {@code pickStrategy} is invalid value 51302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang */ 514a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5151de514256fd3015cf45256f3198ab5472024af9bJungshik Jang void pollDevices(DevicePollingCallback callback, int sourceAddress, int pickStrategy, 5161de514256fd3015cf45256f3198ab5472024af9bJungshik Jang int retryCount) { 517a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 5181de514256fd3015cf45256f3198ab5472024af9bJungshik Jang mCecController.pollDevices(callback, sourceAddress, checkPollStrategy(pickStrategy), 5191de514256fd3015cf45256f3198ab5472024af9bJungshik Jang retryCount); 5200f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5210f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang 5220f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang private int checkPollStrategy(int pickStrategy) { 5233ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int strategy = pickStrategy & HdmiConstants.POLL_STRATEGY_MASK; 5240f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (strategy == 0) { 5250f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid poll strategy:" + pickStrategy); 5260f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5273ecdd832c77483c909fbf90d17d0e6d97ca365eeJungshik Jang int iterationStrategy = pickStrategy & HdmiConstants.POLL_ITERATION_STRATEGY_MASK; 5280f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang if (iterationStrategy == 0) { 5290f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang throw new IllegalArgumentException("Invalid iteration strategy:" + pickStrategy); 5300f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang } 5310f8b4b770c49b83fa8260833d8e1ec5c721a05d3Jungshik Jang return strategy | iterationStrategy; 53202bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang } 53302bb4265ac41e1974ec7d4793e6c2a0ed2adc3c4Jungshik Jang 53460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang List<HdmiCecLocalDevice> getAllLocalDevices() { 53560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang assertRunOnServiceThread(); 53660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return mCecController.getLocalDeviceList(); 53760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 53860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 53979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang Object getServiceLock() { 54079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mLock; 54179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 54279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 54379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 54479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // TODO: Hook up with AudioManager. 5453ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5463ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 547ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void announceSystemAudioModeChange(boolean enabled) { 548ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (IHdmiSystemAudioModeChangeListener listener : mSystemAudioModeChangeListeners) { 549ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeSystemAudioModeChange(listener, enabled); 550ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 551ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 552ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 5533ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang private HdmiCecDeviceInfo createDeviceInfo(int logicalAddress, int deviceType) { 55442c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang // TODO: find better name instead of model name. 55542c9800f4f3acef10d19dca39e8b739546407c04Jungshik Jang String displayName = Build.MODEL; 5563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecDeviceInfo(logicalAddress, 5573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang getPhysicalAddress(), deviceType, getVendorId(), displayName); 5583ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 5593ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang 56078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // Record class that monitors the event of the caller of being killed. Used to clean up 56178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim // the listener list and record list accordingly. 56278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class HotplugEventListenerRecord implements IBinder.DeathRecipient { 56378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final IHdmiHotplugEventListener mListener; 56478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public HotplugEventListenerRecord(IHdmiHotplugEventListener listener) { 56678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mListener = listener; 56778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 56878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 56978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 57078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public void binderDied() { 57178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 57278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(this); 57378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(mListener); 57478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 57778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 5786d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final class DeviceEventListenerRecord implements IBinder.DeathRecipient { 5796d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private final IHdmiDeviceEventListener mListener; 5806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5816d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public DeviceEventListenerRecord(IHdmiDeviceEventListener listener) { 5826d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mListener = listener; 5836d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5846d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 5856d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 586ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 5876d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 5886d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListenerRecords.remove(this); 5896d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim mDeviceEventListeners.remove(mListener); 5906d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5916d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5926d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 5936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 594ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private final class SystemAudioModeChangeListenerRecord implements IBinder.DeathRecipient { 59538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private final IHdmiSystemAudioModeChangeListener mListener; 596ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 597ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public SystemAudioModeChangeListenerRecord(IHdmiSystemAudioModeChangeListener listener) { 598ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mListener = listener; 599ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 600ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 601ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 602ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void binderDied() { 603ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 604ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(this); 605ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(mListener); 606ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 607ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 608ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 609ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 61078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void enforceAccessPermission() { 61178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim getContext().enforceCallingOrSelfPermission(PERMISSION, TAG); 61278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 61378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 61478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private final class BinderService extends IHdmiControlService.Stub { 61578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 61678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim public int[] getSupportedTypes() { 61778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6180340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim // mLocalDevices is an unmodifiable list - no lock necesary. 6190340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim int[] localDevices = new int[mLocalDevices.size()]; 6200340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim for (int i = 0; i < localDevices.length; ++i) { 6210340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim localDevices[i] = mLocalDevices.get(i); 62278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 6230340bbc89f8162f9c2a298c98b03bfcdd1bc6e87Jinsuk Kim return localDevices; 62478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 62578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 62678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 627a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void deviceSelect(final int logicalAddress, final IHdmiControlCallback callback) { 628a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim enforceAccessPermission(); 629a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim runOnServiceThread(new Runnable() { 630a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 631a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim public void run() { 63279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 633a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim if (tv == null) { 634a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 635a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 636a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim return; 637a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 638a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim tv.deviceSelect(logicalAddress, callback); 639a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 640a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim }); 641a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 642a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 643a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim @Override 644a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void portSelect(final int portId, final IHdmiControlCallback callback) { 645a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 646a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 647a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 648a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 649a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 650a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 651a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 652a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 653a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 654a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 6558333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim tv.doManualPortSwitching(portId, callback); 656a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 657a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 658a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 659a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 660a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 661a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void sendKeyEvent(final int keyCode, final boolean isPressed) { 662a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim enforceAccessPermission(); 663a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim runOnServiceThread(new Runnable() { 664a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 665a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim public void run() { 666a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // TODO: sendKeyEvent is for TV device only for now. Allow other 667a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim // local devices of different types to use this as well. 668a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 669a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (tv == null) { 670a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim Slog.w(TAG, "Local tv device not available"); 671a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 672a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 673a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim tv.sendKeyEvent(keyCode, isPressed); 674a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 675a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim }); 676a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 677a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 678a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim @Override 6797fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void oneTouchPlay(final IHdmiControlCallback callback) { 68078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6817fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6827fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6837fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6847fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.oneTouchPlay(callback); 6857fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6867fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 68778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 68878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 68978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 6907fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void queryDisplayStatus(final IHdmiControlCallback callback) { 69178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 6927fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 6937fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 6947fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 6957fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.queryDisplayStatus(callback); 6967fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 6977fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 69878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 69978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 70078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7017fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void addHotplugEventListener(final IHdmiHotplugEventListener listener) { 70278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7037fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7047fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7057fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7067fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.addHotplugEventListener(listener); 7077fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7087fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 70978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 71078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 71178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim @Override 7127fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void removeHotplugEventListener(final IHdmiHotplugEventListener listener) { 71378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim enforceAccessPermission(); 7147fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim runOnServiceThread(new Runnable() { 7157fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim @Override 7167fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim public void run() { 7177fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim HdmiControlService.this.removeHotplugEventListener(listener); 7187fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 7197fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim }); 72078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 7216d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 7226d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 7236d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public void addDeviceEventListener(final IHdmiDeviceEventListener listener) { 7246d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 7256d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim runOnServiceThread(new Runnable() { 7266d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 727ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 7286d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim HdmiControlService.this.addDeviceEventListener(listener); 7296d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7306d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim }); 7316d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 7326d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 7336d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim @Override 7346d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim public List<HdmiPortInfo> getPortInfo() { 7356d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim enforceAccessPermission(); 7366d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim return mPortInfo; 7376d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 738ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 739ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 740ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean canChangeSystemAudioMode() { 741ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 742ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 743ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 744ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 745ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 746e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return tv.hasSystemAudioDevice(); 747ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 748ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 749ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 750ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public boolean getSystemAudioMode() { 751ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 752ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 753ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 754ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return false; 755ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 756ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return tv.getSystemAudioMode(); 757ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 758ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 759ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 760ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void setSystemAudioMode(final boolean enabled, final IHdmiControlCallback callback) { 761ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 762ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang runOnServiceThread(new Runnable() { 763ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 764ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void run() { 765ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 766ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (tv == null) { 767ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Local tv device not available"); 768ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 769ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 770ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 771ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang tv.changeSystemAudioMode(enabled, callback); 772ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 773ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang }); 774ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 775ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 776ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 777ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void addSystemAudioModeChangeListener( 778ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 779ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 780ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.addSystemAudioModeChangeListner(listener); 781ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 782ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 783ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang @Override 784ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang public void removeSystemAudioModeChangeListener( 785ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang final IHdmiSystemAudioModeChangeListener listener) { 786ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang enforceAccessPermission(); 787ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang HdmiControlService.this.removeSystemAudioModeChangeListener(listener); 788ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 78992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 79092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 7919c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void setInputChangeListener(final IHdmiInputChangeListener listener) { 7929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 7939c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiControlService.this.setInputChangeListener(listener); 7949c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 7959c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 7969c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 7979c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public List<HdmiCecDeviceInfo> getInputDevices() { 7989c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim enforceAccessPermission(); 7999c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // No need to hold the lock for obtaining TV device as the local device instance 8009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // is preserved while the HDMI control is enabled. 8019c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 8029c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (tv == null) { 8039c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return Collections.emptyList(); 8049c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return tv.getSafeExternalInputs(); 8069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 8079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 8089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 809160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setControlEnabled(final boolean enabled) { 81092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim enforceAccessPermission(); 81192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 81292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim mHdmiControlEnabled = enabled; 81392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 81492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // TODO: Stop the running actions when disabled, and start 81592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // address allocation/device discovery when enabled. 81692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (!enabled) { 81792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return; 81892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 81992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim runOnServiceThread(new Runnable() { 82092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 82192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim public void run() { 82292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim HdmiCecLocalDeviceTv tv = tv(); 82392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (tv == null) { 82492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return; 82592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 826160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim int value = enabled ? HdmiCec.ENABLED : HdmiCec.DISABLED; 827160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(HdmiCec.OPTION_CEC_ENABLE, value); 828160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 829160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(HdmiCec.OPTION_MHL_ENABLE, value); 830160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 8315344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim tv.launchRoutingControl(false); 83292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 83392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim }); 83492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 835a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 836a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 83741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioVolume(final int oldIndex, final int newIndex, 83841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang final int maxIndex) { 83941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 84041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 84141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 84241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 84341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 84441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 84541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 84641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 84741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 84841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeVolume(oldIndex, newIndex - oldIndex, maxIndex); 84941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 85041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 85141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 85241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 85341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 85441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void setSystemAudioMute(final boolean mute) { 85541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang enforceAccessPermission(); 85641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang runOnServiceThread(new Runnable() { 85741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 85841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang public void run() { 85941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 86041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang if (tv == null) { 86141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang Slog.w(TAG, "Local tv device not available"); 86241d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang return; 86341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 86441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang tv.changeMute(mute); 86541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 86641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang }); 86741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang } 86841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang 86941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang @Override 870a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void setArcMode(final boolean enabled) { 871a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang enforceAccessPermission(); 872a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang runOnServiceThread(new Runnable() { 873a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @Override 874a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang public void run() { 875a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang HdmiCecLocalDeviceTv tv = tv(); 876a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (tv == null) { 87738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Local tv device not available to change arc mode."); 878a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 879a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 880a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 881a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang }); 882a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 883160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 884160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @Override 885160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim public void setOption(final int key, final int value) { 8864d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 887160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (!isTvDevice()) { 888160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return; 889160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 890160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim switch (key) { 891160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim case HdmiCec.OPTION_CEC_AUTO_WAKEUP: 892160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mCecController.setOption(key, value); 893160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 894160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim case HdmiCec.OPTION_CEC_AUTO_DEVICE_OFF: 895160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // No need to pass this option to HAL. 896160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim tv().setAutoDeviceOff(value == HdmiCec.ENABLED); 897160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 898160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim case HdmiCec.OPTION_MHL_INPUT_SWITCHING: // Fall through 899160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim case HdmiCec.OPTION_MHL_POWER_CHARGE: 900160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim if (mMhlController != null) { 901160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mMhlController.setOption(key, value); 902160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 903160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim break; 904160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 905160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 906160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 907160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim private boolean isTvDevice() { 908160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim return tv() != null; 909160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 9104d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 9114d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim @Override 9124d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim public void setProhibitMode(final boolean enabled) { 9134d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim enforceAccessPermission(); 9144d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (!isTvDevice()) { 9154d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return; 9164d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 9174d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim HdmiControlService.this.setProhibitMode(enabled); 9184d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 91978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 92078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 921a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 92279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void oneTouchPlay(final IHdmiControlCallback callback) { 92379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 92479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 9257fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 9267fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 9277fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 9287fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 9297fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 93079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.oneTouchPlay(callback); 93178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 93278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 933a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 93479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void queryDisplayStatus(final IHdmiControlCallback callback) { 93579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 93679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecLocalDevicePlayback source = playback(); 9377fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim if (source == null) { 9387fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.w(TAG, "Local playback device not available"); 9397fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim invokeCallback(callback, HdmiCec.RESULT_SOURCE_NOT_AVAILABLE); 9407fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim return; 9417fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 94279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang source.queryDisplayStatus(callback); 94378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 94478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 94578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void addHotplugEventListener(IHdmiHotplugEventListener listener) { 94678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim HotplugEventListenerRecord record = new HotplugEventListenerRecord(listener); 94778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim try { 94878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().linkToDeath(record, 0); 94978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } catch (RemoteException e) { 95078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim Slog.w(TAG, "Listener already died"); 95178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim return; 95278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 95378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 95478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.add(record); 95578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.add(listener); 95678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 95778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 95878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim 95978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim private void removeHotplugEventListener(IHdmiHotplugEventListener listener) { 96078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim synchronized (mLock) { 96178d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim for (HotplugEventListenerRecord record : mHotplugEventListenerRecords) { 96278d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim if (record.mListener.asBinder() == listener.asBinder()) { 96378d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim listener.asBinder().unlinkToDeath(record, 0); 96478d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListenerRecords.remove(record); 96578d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim break; 96678d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96778d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 96878d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim mHotplugEventListeners.remove(listener); 96978d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 97078d695d8ba532214b02e7f18e0ccf89cf099163dJinsuk Kim } 9717fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim 9726d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim private void addDeviceEventListener(IHdmiDeviceEventListener listener) { 9734893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim DeviceEventListenerRecord record = new DeviceEventListenerRecord(listener); 9744893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 9754893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.asBinder().linkToDeath(record, 0); 9764893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 9774893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.w(TAG, "Listener already died"); 9784893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 9794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 9806d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim synchronized (mLock) { 9814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListeners.add(listener); 9824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim mDeviceEventListenerRecords.add(record); 9834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 9844893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 9854893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim 9864893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim void invokeDeviceEventListeners(HdmiCecDeviceInfo device, boolean activated) { 9874893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim synchronized (mLock) { 9884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim for (IHdmiDeviceEventListener listener : mDeviceEventListeners) { 9894893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim try { 9904893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim listener.onStatusChanged(device, activated); 9914893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } catch (RemoteException e) { 9924893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim Slog.e(TAG, "Failed to report device event:" + e); 9936d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9946d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9956d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9966d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim } 9976d97f5b91c6c82f28a2a3a5d3b922f0e5844e733Jinsuk Kim 998ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void addSystemAudioModeChangeListner(IHdmiSystemAudioModeChangeListener listener) { 999ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang SystemAudioModeChangeListenerRecord record = new SystemAudioModeChangeListenerRecord( 1000ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener); 1001ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1002ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().linkToDeath(record, 0); 1003ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1004ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.w(TAG, "Listener already died"); 1005ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 1006ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1007ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1008ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.add(listener); 1009ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.add(record); 1010ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1011ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1012ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 1013ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void removeSystemAudioModeChangeListener(IHdmiSystemAudioModeChangeListener listener) { 1014ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang synchronized (mLock) { 1015ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang for (SystemAudioModeChangeListenerRecord record : 1016ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords) { 1017ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (record.mListener.asBinder() == listener) { 1018ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.asBinder().unlinkToDeath(record, 0); 1019ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListenerRecords.remove(record); 1020ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang break; 1021ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1022ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1023ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mSystemAudioModeChangeListeners.remove(listener); 1024ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1025ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1026ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 10279c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private final class InputChangeListenerRecord implements IBinder.DeathRecipient { 10289c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim @Override 10299c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim public void binderDied() { 10309c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 10319c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = null; 10329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 10369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim private void setInputChangeListener(IHdmiInputChangeListener listener) { 10379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 10389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListenerRecord = new InputChangeListenerRecord(); 10399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 10409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim listener.asBinder().linkToDeath(mInputChangeListenerRecord, 0); 10419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 10429c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Listener already died"); 10439c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return; 10449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10459c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener = listener; 10469c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 10499c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim void invokeInputChangeListener(int activeAddress) { 10509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim synchronized (mLock) { 10519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim if (mInputChangeListener != null) { 10529c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim HdmiCecDeviceInfo activeSource = getDeviceInfo(activeAddress); 10539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim try { 10549c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mInputChangeListener.onChanged(activeSource); 10559c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } catch (RemoteException e) { 10569c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim Slog.w(TAG, "Exception thrown by IHdmiInputChangeListener: " + e); 10579c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10589c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10599c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10609c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 10619c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 10627fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim private void invokeCallback(IHdmiControlCallback callback, int result) { 10637fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim try { 10647fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim callback.onComplete(result); 10657fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } catch (RemoteException e) { 10667fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 10677fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 10687fe2ae0fe9c24f0a1a5ddf20850069b56af2c2fdJinsuk Kim } 106963a2e0696ce2a04fbe0f1f00cfe9c93189f944daYuncheol Heo 1070ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang private void invokeSystemAudioModeChange(IHdmiSystemAudioModeChangeListener listener, 1071ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang boolean enabled) { 1072ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang try { 1073ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang listener.onStatusChanged(enabled); 1074ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } catch (RemoteException e) { 1075ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang Slog.e(TAG, "Invoking callback failed:" + e); 1076ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1077ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 1078ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 10794893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void announceHotplugEvent(int portId, boolean connected) { 10804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim HdmiHotplugEvent event = new HdmiHotplugEvent(portId, connected); 108160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang synchronized (mLock) { 108260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (IHdmiHotplugEventListener listener : mHotplugEventListeners) { 10834893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim invokeHotplugEventListenerLocked(listener, event); 108460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 108560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 108660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 108760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 10884893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim private void invokeHotplugEventListenerLocked(IHdmiHotplugEventListener listener, 108960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang HdmiHotplugEvent event) { 109060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang try { 109160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang listener.onReceived(event); 109260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } catch (RemoteException e) { 109360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang Slog.e(TAG, "Failed to report hotplug event:" + event.toString(), e); 109460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1095e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang } 1096e81e108c4035ea8933525baa8108cb392f8abf5dJungshik Jang 109760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private static boolean hasSameTopPort(int path1, int path2) { 109860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return (path1 & HdmiConstants.ROUTING_PATH_TOP_MASK) 109960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang == (path2 & HdmiConstants.ROUTING_PATH_TOP_MASK); 110060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 110160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 110279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDeviceTv tv() { 110379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDeviceTv) mCecController.getLocalDevice(HdmiCec.DEVICE_TV); 110479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 110579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 110679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private HdmiCecLocalDevicePlayback playback() { 110779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return (HdmiCecLocalDevicePlayback) mCecController.getLocalDevice(HdmiCec.DEVICE_PLAYBACK); 110860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1109a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 1110a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioManager getAudioManager() { 1111a858d221ff86c497e745222ea15bab141e337636Jungshik Jang return (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE); 1112a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 111392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 111492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim boolean isControlEnabled() { 111592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim synchronized (mLock) { 111692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return mHdmiControlEnabled; 111792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 111892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 111938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 112038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo int getPowerStatus() { 112138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus; 112238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 112338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 112438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerOnOrTransient() { 112538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus == HdmiCec.POWER_STATUS_ON 112638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo || mPowerStatus == HdmiCec.POWER_STATUS_TRANSIENT_TO_ON; 112738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 112838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 112938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandbyOrTransient() { 113038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus == HdmiCec.POWER_STATUS_STANDBY 113138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo || mPowerStatus == HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY; 113238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 113338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 113438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo boolean isPowerStandby() { 113538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return mPowerStatus == HdmiCec.POWER_STATUS_STANDBY; 113638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 113738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 113838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 113938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void wakeUp() { 114038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 114138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 114238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.wakeUp(SystemClock.uptimeMillis()); 114338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets 114438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onWakeUp(). 114538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 114638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 114738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 114838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void standby() { 114938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 115038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = true; 115138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo PowerManager pm = (PowerManager) getContext().getSystemService(Context.POWER_SERVICE); 115238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo pm.goToSleep(SystemClock.uptimeMillis()); 115338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // PowerManger will send the broadcast Intent.ACTION_SCREEN_OFF and after this gets 115438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // the intent, the sequence will continue at onStandby(). 115538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 115638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 115738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 115838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onWakeUp() { 115938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 116038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mPowerStatus = HdmiCec.POWER_STATUS_TRANSIENT_TO_ON; 116138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mCecController != null) { 116238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mCecController.setOption(HdmiCec.OPTION_CEC_SERVICE_CONTROL, HdmiCec.ENABLED); 116338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo initializeLocalDevices(mLocalDevices); 116438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else { 116538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.i(TAG, "Device does not support HDMI-CEC."); 116638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 116738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // TODO: Initialize MHL local devices. 116838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 116938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 117038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 117138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo private void onStandby() { 117238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 117338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mPowerStatus = HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY; 117438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 117538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo device.onTransitionToStandby(mStandbyMessageReceived); 117638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 117738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 117838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 117938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 118038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * Called when there are the outstanding actions in the local devices. 118138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * This callback is used to wait for when the action queue is empty 118238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * during the power state transition to standby. 118338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 118438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 118538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo void onPendingActionsCleared() { 118638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 118738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mPowerStatus != HdmiCec.POWER_STATUS_TRANSIENT_TO_STANDBY) { 118838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 118938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 119038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mPowerStatus = HdmiCec.POWER_STATUS_STANDBY; 119138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { 119238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo device.onStandBy(mStandbyMessageReceived); 119338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 119438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mStandbyMessageReceived = false; 119538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mCecController.setOption(HdmiCec.OPTION_CEC_SERVICE_CONTROL, HdmiCec.DISABLED); 119638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 11974d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 11984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 11994d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 12004d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mProhibitMode; 12014d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12034d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim 12044d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim void setProhibitMode(boolean enabled) { 12054d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim synchronized (mLock) { 12064d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim mProhibitMode = enabled; 12074d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12084d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 12090792d37385e60aa8d73f8df174d0a32f4f618bc4Jungshik Jang} 1210