12918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/* 22918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Copyright (C) 2014 The Android Open Source Project 32918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * 42918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Licensed under the Apache License, Version 2.0 (the "License"); 52918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * you may not use this file except in compliance with the License. 62918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * You may obtain a copy of the License at 72918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * 82918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * http://www.apache.org/licenses/LICENSE-2.0 92918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * 102918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Unless required by applicable law or agreed to in writing, software 112918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * distributed under the License is distributed on an "AS IS" BASIS, 122918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * See the License for the specific language governing permissions and 142918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * limitations under the License. 152918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */ 162918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 172918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimpackage com.android.server.hdmi; 182918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 19e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.CLEAR_TIMER_STATUS_CEC_DISABLE; 20e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION; 21e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE; 2212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CEC_DISABLED; 2312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION; 2412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN; 25339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jangimport static android.hardware.hdmi.HdmiControlManager.OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT; 26e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED; 27e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION; 28e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE; 29e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_ANALOGUE; 30e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_DIGITAL; 31e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport static android.hardware.hdmi.HdmiControlManager.TIMER_RECORDING_TYPE_EXTERNAL; 3212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 33c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kimimport android.hardware.hdmi.HdmiControlManager; 345008486b09c588bf3409b70d9ee29225e8593c64Jinsuk Kimimport android.hardware.hdmi.HdmiDeviceInfo; 352ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kimimport android.hardware.hdmi.HdmiPortInfo; 36b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport android.hardware.hdmi.HdmiRecordSources; 3712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jangimport android.hardware.hdmi.HdmiTimerRecordSources; 3860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport android.hardware.hdmi.IHdmiControlCallback; 39b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jangimport android.media.AudioManager; 40a858d221ff86c497e745222ea15bab141e337636Jungshik Jangimport android.media.AudioSystem; 417fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputInfo; 427fa3a66470d2133796defd14a0600578758882acJinsuk Kimimport android.media.tv.TvInputManager.TvInputCallback; 43a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kimimport android.os.RemoteException; 447ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kimimport android.provider.Settings.Global; 454fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kimimport android.util.ArraySet; 46092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangimport android.util.Slog; 4779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.util.SparseArray; 485bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kimimport android.util.SparseBooleanArray; 49092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 5079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport com.android.internal.annotations.GuardedBy; 51959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 5260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jangimport com.android.server.hdmi.DeviceDiscoveryAction.DeviceDiscoveryCallback; 53a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 54e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jangimport com.android.server.hdmi.HdmiControlService.SendMessageCallback; 558f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jangimport java.io.UnsupportedEncodingException; 5679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.ArrayList; 57b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jangimport java.util.Arrays; 584fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kimimport java.util.Collection; 590a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kimimport java.util.Collections; 604fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kimimport java.util.Iterator; 610a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kimimport java.util.List; 626e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kimimport java.util.HashMap; 632918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 642918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/** 652918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Represent a logical device of type TV residing in Android system. 662918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */ 672918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimfinal class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { 68092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static final String TAG = "HdmiCecLocalDeviceTv"; 692918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 7012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang // Whether ARC is available or not. "true" means that ARC is established between TV and 71a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // AVR as audio receiver. 72a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 73a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang private boolean mArcEstablished = false; 74a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 755bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim // Stores whether ARC feature is enabled per port. True by default for all the ARC-enabled ports. 765bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim private final SparseBooleanArray mArcFeatureEnabled = new SparseBooleanArray(); 7779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 78377dcbd53af4529c352d453424539b069909fce4Jungshik Jang // Whether System audio mode is activated or not. 79377dcbd53af4529c352d453424539b069909fce4Jungshik Jang // This becomes true only when all system audio sequences are finished. 80fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang @GuardedBy("mLock") 81377dcbd53af4529c352d453424539b069909fce4Jungshik Jang private boolean mSystemAudioActivated = false; 8279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 838333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // The previous port id (input) before switching to the new one. This is remembered in order to 848333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // be able to switch to it upon receiving <Inactive Source> from currently active source. 858333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // This remains valid only when the active source was switched via one touch play operation 868333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // (either by TV or source device). Manual port switching invalidates this value to 87c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim // Constants.PORT_INVALID, for which case <Inactive Source> does not do anything. 888333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @GuardedBy("mLock") 898333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim private int mPrevPortId; 908333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 918fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @GuardedBy("mLock") 92c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim private int mSystemAudioVolume = Constants.UNKNOWN_VOLUME; 938fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 948fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @GuardedBy("mLock") 958fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang private boolean mSystemAudioMute = false; 968fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 97fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang // Copy of mDeviceInfos to guarantee thread-safety. 98fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang @GuardedBy("mLock") 9961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private List<HdmiDeviceInfo> mSafeAllDeviceInfos = Collections.emptyList(); 1009c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim // All external cec input(source) devices. Does not include system audio device. 101fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang @GuardedBy("mLock") 10261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private List<HdmiDeviceInfo> mSafeExternalInputs = Collections.emptyList(); 103fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 10479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Map-like container of all cec devices including local ones. 1058960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim // device id is used as key of container. 106fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang // This is not thread-safe. For external purpose use mSafeDeviceInfos. 10761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private final SparseArray<HdmiDeviceInfo> mDeviceInfos = new SparseArray<>(); 10879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 109160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim // If true, TV going to standby mode puts other devices also to standby. 110160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim private boolean mAutoDeviceOff; 111160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 112544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim // If true, TV wakes itself up when receiving <Text/Image View On>. 113544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim private boolean mAutoWakeup; 114544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim 115bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim // List of the logical address of local CEC devices. Unmodifiable, thread-safe. 116bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim private List<Integer> mLocalDeviceAddresses; 117bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 11825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo private final HdmiCecStandbyModeHandler mStandbyHandler; 11925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 120d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim // If true, do not do routing control/send active source for internal source. 121d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim // Set to true when the device was woken up by <Text/Image View On>. 122d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim private boolean mSkipRoutingControl; 123d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim 1244fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // Set of physical addresses of CEC switches on the CEC bus. Managed independently from 1254fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // other CEC devices since they might not have logical address. 1264fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private final ArraySet<Integer> mCecSwitches = new ArraySet<Integer>(); 1274fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 1287fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Message buffer used to buffer selected messages to process later. <Active Source> 1297fa3a66470d2133796defd14a0600578758882acJinsuk Kim // from a source device, for instance, needs to be buffered if the device is not 1307fa3a66470d2133796defd14a0600578758882acJinsuk Kim // discovered yet. The buffered commands are taken out and when they are ready to 1317fa3a66470d2133796defd14a0600578758882acJinsuk Kim // handle. 1327fa3a66470d2133796defd14a0600578758882acJinsuk Kim private final DelayedMessageBuffer mDelayedMessageBuffer = new DelayedMessageBuffer(this); 1337fa3a66470d2133796defd14a0600578758882acJinsuk Kim 1347fa3a66470d2133796defd14a0600578758882acJinsuk Kim // Defines the callback invoked when TV input framework is updated with input status. 1357fa3a66470d2133796defd14a0600578758882acJinsuk Kim // We are interested in the notification for HDMI input addition event, in order to 1367fa3a66470d2133796defd14a0600578758882acJinsuk Kim // process any CEC commands that arrived before the input is added. 1377fa3a66470d2133796defd14a0600578758882acJinsuk Kim private final TvInputCallback mTvInputCallback = new TvInputCallback() { 1387fa3a66470d2133796defd14a0600578758882acJinsuk Kim @Override 1397fa3a66470d2133796defd14a0600578758882acJinsuk Kim public void onInputAdded(String inputId) { 1407fa3a66470d2133796defd14a0600578758882acJinsuk Kim TvInputInfo tvInfo = mService.getTvInputManager().getTvInputInfo(inputId); 141a22d77e24737b785a33987647758cd3c1db85527Terry Heo if (tvInfo == null) return; 1427fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiDeviceInfo info = tvInfo.getHdmiDeviceInfo(); 1436e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim if (info == null) return; 1446e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim addTvInput(inputId, info.getId()); 1456e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim if (info.isCecDevice()) { 1466e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim processDelayedActiveSource(info.getLogicalAddress()); 1477fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1487fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1496e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1506e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @Override 1516e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim public void onInputRemoved(String inputId) { 1526e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim removeTvInput(inputId); 1536e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1547fa3a66470d2133796defd14a0600578758882acJinsuk Kim }; 1557fa3a66470d2133796defd14a0600578758882acJinsuk Kim 1566e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // Keeps the mapping (TV input ID, HDMI device ID) to keep track of the TV inputs ready to 1576e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // accept input switching request from HDMI devices. Requests for which the corresponding 1586e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // input ID is not yet registered by TV input framework need to be buffered for delayed 1596e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // processing. 1606e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private final HashMap<String, Integer> mTvInputs = new HashMap<>(); 1616e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1626e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1636e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private void addTvInput(String inputId, int deviceId) { 1646e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1656e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.put(inputId, deviceId); 1666e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1676e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1686e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1696e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private void removeTvInput(String inputId) { 1706e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1716e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.remove(inputId); 1726e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1736e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1746e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @Override 1756e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1766e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim protected boolean isInputReady(int deviceId) { 1776e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1786e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim return mTvInputs.containsValue(deviceId); 1796e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1806e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 181f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private SelectRequestBuffer mSelectRequestBuffer; 182f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDeviceTv(HdmiControlService service) { 18461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang super(service, HdmiDeviceInfo.DEVICE_TV); 185c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPrevPortId = Constants.INVALID_PORT_ID; 186544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 187544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim true); 188544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true); 18925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); 1908b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang } 1912918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1928b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang @Override 193a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 194fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo protected void onAddressAllocated(int logicalAddress, int reason) { 19579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 1965bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim List<HdmiPortInfo> ports = mService.getPortInfo(); 1975bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim for (HdmiPortInfo port : ports) { 1985bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim mArcFeatureEnabled.put(port.getId(), port.isArcSupported()); 1995bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 2007fa3a66470d2133796defd14a0600578758882acJinsuk Kim mService.registerTvInputCallback(mTvInputCallback); 2013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 2023ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress, mService.getPhysicalAddress(), mDeviceType)); 2033ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 2043ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress, mService.getVendorId())); 2054fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim mCecSwitches.add(mService.getPhysicalAddress()); // TV is a CEC switch too. 2066e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.clear(); 207d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE); 208fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC && 209fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo reason != HdmiControlService.INITIATED_BY_BOOT_UP); 210bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim mLocalDeviceAddresses = initLocalDeviceAddresses(); 211f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim resetSelectRequestBuffer(); 21260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang launchDeviceDiscovery(); 2136f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang } 2146f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang 215bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 216bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @ServiceThreadOnly 217bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim private List<Integer> initLocalDeviceAddresses() { 218bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim assertRunOnServiceThread(); 219bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim List<Integer> addresses = new ArrayList<>(); 220bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { 221bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim addresses.add(device.getDeviceInfo().getLogicalAddress()); 222bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 223bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return Collections.unmodifiableList(addresses); 224bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 225bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 226f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 227f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim @ServiceThreadOnly 228f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim public void setSelectRequestBuffer(SelectRequestBuffer requestBuffer) { 229f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim assertRunOnServiceThread(); 230f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer = requestBuffer; 231f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 232f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 233f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim @ServiceThreadOnly 234f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim private void resetSelectRequestBuffer() { 235f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim assertRunOnServiceThread(); 236f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim setSelectRequestBuffer(SelectRequestBuffer.EMPTY_BUFFER); 237f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim } 238f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 239af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim @Override 240af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected int getPreferredAddress() { 241d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return Constants.ADDR_TV; 242af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim } 243af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 244af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim @Override 245af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected void setPreferredAddress(int addr) { 246d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim Slog.w(TAG, "Preferred addres will not be stored for TV"); 247af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim } 248af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 24925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @Override 25025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @ServiceThreadOnly 25125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean dispatchMessage(HdmiCecMessage message) { 25225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo assertRunOnServiceThread(); 25325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (mService.isPowerStandby() && mStandbyHandler.handleCommand(message)) { 25425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return true; 25525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 25625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return super.onMessage(message); 25725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 25825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 259a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim /** 260a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Performs the action 'device select', or 'one touch play' initiated by TV. 261a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * 2628960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * @param id id of HDMI device to select 263a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * @param callback callback object to report the result with 264a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim */ 265a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2668960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim void deviceSelect(int id, IHdmiControlCallback callback) { 26779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 2688960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo targetDevice = mDeviceInfos.get(id); 2698960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (targetDevice == null) { 2708960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); 2718960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return; 2728960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 2738960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim int targetAddress = targetDevice.getLogicalAddress(); 27458500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim ActiveSource active = getActiveSource(); 2756b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON 2766b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara && active.isValid() 2776b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara && targetAddress == active.logicalAddress) { 27858500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 27958500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim return; 28058500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim } 281c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (targetAddress == Constants.ADDR_INTERNAL) { 2825ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim handleSelectInternalSource(); 2835ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim // Switching to internal source is always successful even when CEC control is disabled. 28472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(targetAddress, mService.getPhysicalAddress()); 2857e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim setActivePath(mService.getPhysicalAddress()); 2865ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 2878333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return; 2888333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 28909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isControlEnabled()) { 2908960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim setActiveSource(targetDevice); 29109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 29209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim return; 29309ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 29479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(DeviceSelectAction.class); 29579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(new DeviceSelectAction(this, targetDevice, callback)); 296a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 297a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 2988333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 2995ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim private void handleSelectInternalSource() { 3008333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 3018333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #18 30272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) { 3038333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim updateActiveSource(mAddress, mService.getPhysicalAddress()); 304d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim if (mSkipRoutingControl) { 305d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = false; 306d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim return; 307d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim } 3088333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( 3098333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mAddress, mService.getPhysicalAddress()); 3108333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mService.sendCecCommand(activeSource); 3118333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3128333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3138333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3148333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 31572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveSource(int logicalAddress, int physicalAddress) { 31672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim assertRunOnServiceThread(); 31772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress)); 31872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 31972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 32072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @ServiceThreadOnly 32172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveSource(ActiveSource newActive) { 3228333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 3238333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #14 32472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mActiveSource.equals(newActive)) { 3258333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return; 3268333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 32772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(newActive); 32872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress = newActive.logicalAddress; 3298960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) { 33072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) { 3318333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim setPrevPortId(getActivePortId()); 3328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3338333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Show the OSD banner related to the new active source device. 3348333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } else { 3358333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: If displayed, remove the OSD banner related to the previous 3368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // active source device. 3378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3388333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3398333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3402b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int getPortId(int physicalAddress) { 3412b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mService.pathToPortId(physicalAddress); 3422b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3432b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 344a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 3458333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * Returns the previous port id kept to handle input switching on <Inactive Source>. 3468333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim */ 3478333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim int getPrevPortId() { 3488333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 3498333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return mPrevPortId; 3508333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3518333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3528333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3538333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim /** 3548333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * Sets the previous port id. INVALID_PORT_ID invalidates it, hence no actions will be 3558333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * taken for <Inactive Source>. 356a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 3578333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void setPrevPortId(int portId) { 3588333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 3598333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mPrevPortId = portId; 3608333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3618333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3628333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 363a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 36472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveInput(int path, boolean notifyInputChange) { 365a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim assertRunOnServiceThread(); 3668333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #15 36772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActivePath(path); 36872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim // TODO: Handle PAP/PIP case. 36972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim // Show OSD port change banner 37072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (notifyInputChange) { 37172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource activeSource = getActiveSource(); 3728960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(activeSource.logicalAddress); 37372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (info == null) { 3746ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim info = mService.getDeviceInfoByPort(getActivePortId()); 3756ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim if (info == null) { 3766ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim // No CEC/MHL device is present at the port. Attempt to switch to 3776ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim // the hardware port itself for non-CEC devices that may be connected. 3786ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim info = new HdmiDeviceInfo(path, getActivePortId()); 3796ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 38072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 38172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mService.invokeInputChangeListener(info); 38272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 3838333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3848333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3858333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3868333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void doManualPortSwitching(int portId, IHdmiControlCallback callback) { 3878333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 3888333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #20 38909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isValidPortId(portId)) { 390c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 391a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 392a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 39372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (portId == getActivePortId()) { 39472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 39572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 39672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 39743c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim mActiveSource.invalidate(); 39809ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isControlEnabled()) { 39909ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim setActivePortId(portId); 40009ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 40109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim return; 40209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 4031f8d1c576f06ed63c21d175fb0c86db596f59353Jinsuk Kim int oldPath = getActivePortId() != Constants.INVALID_PORT_ID 4041f8d1c576f06ed63c21d175fb0c86db596f59353Jinsuk Kim ? mService.portIdToPath(getActivePortId()) : getDeviceInfo().getPhysicalAddress(); 405d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim setActivePath(oldPath); 406d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim if (mSkipRoutingControl) { 407d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = false; 408d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim return; 409d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim } 410a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim int newPath = mService.portIdToPath(portId); 411546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(oldPath, newPath, true, callback); 412546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim } 413546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim 414546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim @ServiceThreadOnly 415546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim void startRoutingControl(int oldPath, int newPath, boolean queryDevicePowerStatus, 416546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim IHdmiControlCallback callback) { 417546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim assertRunOnServiceThread(); 418546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim if (oldPath == newPath) { 419546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim return; 420546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim } 421a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecMessage routingChange = 422a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath); 423a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim mService.sendCecCommand(routingChange); 42472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim removeAction(RoutingControlAction.class); 425546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim addAndStartAction( 426546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim new RoutingControlAction(this, newPath, queryDevicePowerStatus, callback)); 427a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 428a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 429f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 430cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim int getPowerStatus() { 431f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 432cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim return mService.getPowerStatus(); 433cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim } 434cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim 435a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 436a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Sends key to a target CEC device. 437a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * 438fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * @param keyCode key code to send. Defined in {@link android.view.KeyEvent}. 439c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * @param isPressed true if this is key press event 440a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 441c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim @Override 442a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 443c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim protected void sendKeyEvent(int keyCode, boolean isPressed) { 444a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim assertRunOnServiceThread(); 445b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo if (!HdmiCecKeycode.isSupportedKeycode(keyCode)) { 446b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo Slog.w(TAG, "Unsupported key: " + keyCode); 447b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo return; 448b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo } 449a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim List<SendKeyAction> action = getActions(SendKeyAction.class); 450454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim int logicalAddress = findKeyReceiverAddress(); 451454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim if (logicalAddress == mAddress) { 452454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim Slog.w(TAG, "Discard key event to itself :" + keyCode + " pressed:" + isPressed); 453454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim return; 454454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim } 455a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (!action.isEmpty()) { 456a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim action.get(0).processKeyEvent(keyCode, isPressed); 457a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } else { 4587543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (isPressed) { 4597543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (logicalAddress != Constants.ADDR_INVALID) { 4607543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode)); 4617543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return; 4627543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 463a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 4647543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed); 465a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 466a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 467a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 4687543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim private int findKeyReceiverAddress() { 4697543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (getActiveSource().isValid()) { 4707543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return getActiveSource().logicalAddress; 4717543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4727543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim HdmiDeviceInfo info = getDeviceInfoByPath(getActivePath()); 4737543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (info != null) { 4747543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return info.getLogicalAddress(); 4757543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4767543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return Constants.ADDR_INVALID; 4777543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4787543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim 479a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim private static void invokeCallback(IHdmiControlCallback callback, int result) { 4804893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim if (callback == null) { 4814893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 4824893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 483a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim try { 484a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim callback.onComplete(result); 485a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } catch (RemoteException e) { 486a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 487a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 488a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 489a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 490092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang @Override 491a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4928333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleActiveSource(HdmiCecMessage message) { 4938333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 49472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress = message.getSource(); 49572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); 496bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); 497bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim if (info == null) { 4987fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (!handleNewDeviceAtTheTailOfActivePath(physicalAddress)) { 499cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim HdmiLogger.debug("Device info %X not found; buffering the command", logicalAddress); 5007fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.add(message); 5017fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 502455f09d818d23d918d0146c91f977774cbfb0657Donghyun Cho } else if (isInputReady(info.getId()) 503455f09d818d23d918d0146c91f977774cbfb0657Donghyun Cho || info.getDeviceType() == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) { 5047cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON); 50572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress); 506bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType()); 507455f09d818d23d918d0146c91f977774cbfb0657Donghyun Cho } else { 508455f09d818d23d918d0146c91f977774cbfb0657Donghyun Cho HdmiLogger.debug("Input not ready for device: %X; buffering the command", info.getId()); 509455f09d818d23d918d0146c91f977774cbfb0657Donghyun Cho mDelayedMessageBuffer.add(message); 51092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 5118333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5128333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5138333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5148333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 5158333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 5168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleInactiveSource(HdmiCecMessage message) { 5178333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 5188333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #10 5198333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Ignore <Inactive Source> from non-active source device. 52172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (getActiveSource().logicalAddress != message.getSource()) { 5228333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5238333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5244d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (isProhibitMode()) { 5258333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5268333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5278333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim int portId = getPrevPortId(); 528c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 5298333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Do this only if TV is not showing multiview like PIP/PAP. 5308333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5318960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo inactiveSource = getCecDeviceInfo(message.getSource()); 5328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim if (inactiveSource == null) { 5338333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5348333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5358333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim if (mService.pathToPortId(inactiveSource.getPhysicalAddress()) == portId) { 5368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5388333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Switch the TV freeze mode off 5398333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5408333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim doManualPortSwitching(portId, null); 541c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim setPrevPortId(Constants.INVALID_PORT_ID); 542cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } else { 543cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // No HDMI port to switch to was found. Notify the input change listers to 544cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // switch to the lastly shown internal input. 545cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim mActiveSource.invalidate(); 546cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim setActivePath(Constants.INVALID_PHYSICAL_ADDRESS); 547cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE); 5488333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5498333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5508333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5518333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5528333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 5538333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 5548333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleRequestActiveSource(HdmiCecMessage message) { 5558333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 5568333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #19 55772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mAddress == getActiveSource().logicalAddress) { 5588333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mService.sendCecCommand( 55992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath())); 5608333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5618333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5628333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5638333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5648333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 5658333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 566092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetMenuLanguage(HdmiCecMessage message) { 56779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 568f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang if (!broadcastMenuLanguage(mService.getLanguage())) { 569092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString()); 570092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 571092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 572092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 573092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 5741ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 5751ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo boolean broadcastMenuLanguage(String language) { 5761ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 5771ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( 5781ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mAddress, language); 5791ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (command != null) { 5801ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mService.sendCecCommand(command); 5811ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo return true; 5821ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 5831ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo return false; 5841ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 5851ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 58660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang @Override 587a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 58860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { 58979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5904fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int path = HdmiUtils.twoBytesToInt(message.getParams()); 5914fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int address = message.getSource(); 592bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim int type = message.getParams()[2]; 5934fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 594bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (updateCecSwitchInfo(address, type, path)) return true; 5954fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 596092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // Ignore if [Device Discovery Action] is going on. 59779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (hasAction(DeviceDiscoveryAction.class)) { 5984fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim Slog.i(TAG, "Ignored while Device Discovery Action is in progress: " + message); 599092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 600092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 601092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 6024b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim if (!isInDeviceList(address, path)) { 6038f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang handleNewDeviceAtTheTailOfActivePath(path); 60492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 6057cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim 6067cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim // Add the device ahead with default information to handle <Active Source> 6077cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim // promptly, rather than waiting till the new device action is finished. 6087cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(address, path, getPortId(path), type, 6097cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address)); 6107cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim addCecDevice(deviceInfo); 611bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim startNewDeviceAction(ActiveSource.of(address, path), type); 61292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; 61392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 61492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 6154480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 6164480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleReportPowerStatus(HdmiCecMessage command) { 6174480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int newStatus = command.getParams()[0] & 0xFF; 6184480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang updateDevicePowerStatus(command.getSource(), newStatus); 6194480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6204480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6214480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6224480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 6234480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleTimerStatus(HdmiCecMessage message) { 6244480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Do nothing. 6254480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6264480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6274480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6284480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 6294480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleRecordStatus(HdmiCecMessage message) { 6304480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Do nothing. 6314480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6324480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6334480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 634bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim boolean updateCecSwitchInfo(int address, int type, int path) { 635bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (address == Constants.ADDR_UNREGISTERED 636bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim && type == HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH) { 637bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim mCecSwitches.add(path); 638bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim updateSafeDeviceInfoList(); 639bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim return true; // Pure switch does not need further processing. Return here. 640bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 641bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (type == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) { 642bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim mCecSwitches.add(path); 643bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 644bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim return false; 645bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 646bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim 647bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim void startNewDeviceAction(ActiveSource activeSource, int deviceType) { 64897affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang for (NewDeviceAction action : getActions(NewDeviceAction.class)) { 64997affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // If there is new device action which has the same logical address and path 65097affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // ignore new request. 65197affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // NewDeviceAction is created whenever it receives <Report Physical Address>. 65297affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // And there is a chance starting NewDeviceAction for the same source. 65397affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // Usually, new device sends <Report Physical Address> when it's plugged 65497affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // in. However, TV can detect a new device from HotPlugDetectionAction, 65597affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // which sends <Give Physical Address> to the source for newly detected 65697affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // device. 65772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (action.isActionOf(activeSource)) { 65897affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang return; 65997affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 66097affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 66197affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang 66272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, 663bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim activeSource.physicalAddress, deviceType)); 66497affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 66597affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang 6667fa3a66470d2133796defd14a0600578758882acJinsuk Kim private boolean handleNewDeviceAtTheTailOfActivePath(int path) { 66792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #22 66892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (isTailOfActivePath(path, getActivePath())) { 66992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 6707c3a95633d307c4be30c9dbbf1071063aa7a3c64Jinsuk Kim setActivePath(newPath); 671546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, false, null); 6727fa3a66470d2133796defd14a0600578758882acJinsuk Kim return true; 67392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 6747fa3a66470d2133796defd14a0600578758882acJinsuk Kim return false; 67592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 676092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 67792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim /** 67892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * Whether the given path is located in the tail of current active path. 67992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * 68092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param path to be tested 68192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param activePath current active path 68292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @return true if the given path is located in the tail of current active path; otherwise, 68392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * false 68492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim */ 68592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim static boolean isTailOfActivePath(int path, int activePath) { 68692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // If active routing path is internal source, return false. 68792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (activePath == 0) { 68892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 68992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 69092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim for (int i = 12; i >= 0; i -= 4) { 69192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int curActivePath = (activePath >> i) & 0xF; 69292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (curActivePath == 0) { 69392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; 69492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } else { 69592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int curPath = (path >> i) & 0xF; 69692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (curPath != curActivePath) { 69792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 69892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 69992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 70092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 70192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 70292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 70392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 70492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 70592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @ServiceThreadOnly 70692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim protected boolean handleRoutingChange(HdmiCecMessage message) { 70792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim assertRunOnServiceThread(); 70892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #21 70992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim byte[] params = message.getParams(); 71092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int currentPath = HdmiUtils.twoBytesToInt(params); 71192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) { 71243c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim mActiveSource.invalidate(); 71392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim removeAction(RoutingControlAction.class); 71443c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim int newPath = HdmiUtils.twoBytesToInt(params, 2); 71504fd28046acc2ac74339ed94cec76a0bfda846f7Jinsuk Kim addAndStartAction(new RoutingControlAction(this, newPath, true, null)); 71692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 717092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 718092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 7190a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim 7200a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim @Override 721a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7228fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang protected boolean handleReportAudioStatus(HdmiCecMessage message) { 7238fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 7248fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 7258fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang byte params[] = message.getParams(); 7268fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int mute = params[0] & 0x80; 7278fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int volume = params[0] & 0x7F; 7288fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang setAudioStatus(mute == 0x80, volume); 7298fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return true; 7308fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 7318fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 73238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 73338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 73438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleTextViewOn(HdmiCecMessage message) { 73538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 736c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim 737c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // Note that <Text View On> (and <Image View On>) command won't be handled here in 738c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // most cases. A dedicated microcontroller should be in charge while Android system 739c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // is in sleep mode, and the command need not be passed up to this service. 740c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // The only situation where the command reaches this handler is that sleep mode is 741c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // implemented in such a way that Android system is not really put to standby mode 742c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // but only the display is set to blank. Then the command leads to the effect of 743c854c95b1b90d90c5906da2a21c0129a8098d3bfJinsuk Kim // turning on the display by the invocation of PowerManager.wakeUp(). 744544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim if (mService.isPowerStandbyOrTransient() && mAutoWakeup) { 74538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.wakeUp(); 74638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 74738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 74838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 74938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 75038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 75138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 75238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleImageViewOn(HdmiCecMessage message) { 75338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 75438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Currently, it's the same as <Text View On>. 75538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleTextViewOn(message); 75638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 75738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 7588f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang @Override 7598f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang @ServiceThreadOnly 7608f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang protected boolean handleSetOsdName(HdmiCecMessage message) { 7618f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang int source = message.getSource(); 7628960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo deviceInfo = getCecDeviceInfo(source); 7638f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang // If the device is not in device list, ignore it. 7648f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang if (deviceInfo == null) { 7658f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.e(TAG, "No source device info for <Set Osd Name>." + message); 7668f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7678f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7688f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang String osdName = null; 7698f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang try { 7708f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang osdName = new String(message.getParams(), "US-ASCII"); 7718f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } catch (UnsupportedEncodingException e) { 7728f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.e(TAG, "Invalid <Set Osd Name> request:" + message, e); 7738f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7748f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7758f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 7768f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang if (deviceInfo.getDisplayName().equals(osdName)) { 7778f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.i(TAG, "Ignore incoming <Set Osd Name> having same osd name:" + message); 7788f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7798f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7808f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 78161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang addCecDevice(new HdmiDeviceInfo(deviceInfo.getLogicalAddress(), 7822b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(), 7832b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName)); 7848f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7858f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7868f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 787a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 78860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void launchDeviceDiscovery() { 78979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 79079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang clearDeviceInfoList(); 79179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, 79260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang new DeviceDiscoveryCallback() { 79360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang @Override 79461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos) { 79561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : deviceInfos) { 79679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addCecDevice(info); 79760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 79860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 79960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // Since we removed all devices when it's start and 80060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // device discovery action does not poll local devices, 80160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // we should put device info of local device manually here 80260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { 80379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addCecDevice(device.getDeviceInfo()); 80460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 80560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 806f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim mSelectRequestBuffer.process(); 807f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim resetSelectRequestBuffer(); 808f98b9e87f9258d4ffb53859de2a138e72174cc23Jinsuk Kim 80979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); 810410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); 811187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang 812187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // If there is AVR, initiate System Audio Auto initiation action, 813187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // which turns on and off system audio according to last system 814187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // audio setting. 815339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 816339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (avr != null) { 817339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang onNewAvrAdded(avr); 818951e3e42f5943d90b74d9feb9fbc224afa59ed31Wally Yau } else { 819951e3e42f5943d90b74d9feb9fbc224afa59ed31Wally Yau setSystemAudioMode(false, true); 820187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang } 82160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 82260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang }); 82379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 82479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 82579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 826339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 827339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void onNewAvrAdded(HdmiDeviceInfo avr) { 828339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 829c21f63aa9514fb5f34e195fade88f8545d935992Donghyun Cho addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress())); 8305bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (isArcFeatureEnabled(avr.getPortId()) 8315bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim && !hasAction(SetArcTransmissionStateAction.class)) { 832339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang startArcAction(true); 833339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 834339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 835339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 83679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Clear all device info. 837a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 83879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void clearDeviceInfoList() { 83979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 84061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : mSafeExternalInputs) { 84161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 84249b47bbef8a8d27e9707d5d24848040519586a7aJinsuk Kim } 84379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mDeviceInfos.clear(); 844fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 84579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 84679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 847a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 848c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo // Seq #32 849ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) { 850ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang assertRunOnServiceThread(); 851c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo if (!mService.isControlEnabled() || hasAction(DeviceDiscoveryAction.class)) { 852c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo setSystemAudioMode(false, true); 853c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 854c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo return; 855c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo } 85661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 857ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (avr == null) { 858c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo setSystemAudioMode(false, true); 859d05f67f9721e1f9194a1f57cf7481b4be65366b3Yuncheol Heo invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); 860ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 861ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 862ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 863ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang addAndStartAction( 864ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang new SystemAudioActionFromTv(this, avr.getLogicalAddress(), enabled, callback)); 865ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 866ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 867ca5be9a8fbc91daece39c851ca3f09d60b24b870Jungshik Jang // # Seq 25 8687ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void setSystemAudioMode(boolean on, boolean updateSetting) { 8692e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on); 870473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang 871377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (updateSetting) { 872377dcbd53af4529c352d453424539b069909fce4Jungshik Jang mService.writeBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, on); 873377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 874377dcbd53af4529c352d453424539b069909fce4Jungshik Jang updateAudioManagerForSystemAudio(on); 87579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 876377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (mSystemAudioActivated != on) { 877377dcbd53af4529c352d453424539b069909fce4Jungshik Jang mSystemAudioActivated = on; 878ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mService.announceSystemAudioModeChange(on); 87979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 88079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 88179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 88279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 883377dcbd53af4529c352d453424539b069909fce4Jungshik Jang private void updateAudioManagerForSystemAudio(boolean on) { 8846b096d349b8ea879ee152a50df66427c919adabaJungshik Jang int device = mService.getAudioManager().setHdmiSystemAudioSupported(on); 8856b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); 886377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 887377dcbd53af4529c352d453424539b069909fce4Jungshik Jang 888377dcbd53af4529c352d453424539b069909fce4Jungshik Jang boolean isSystemAudioActivated() { 88986a1e5a16ed6d49ecbdfe78c3ca7a9afc7814264Jinsuk Kim if (!hasSystemAudioDevice()) { 890377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return false; 891377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 89279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 893377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return mSystemAudioActivated; 89479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 89579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 89679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 897377dcbd53af4529c352d453424539b069909fce4Jungshik Jang boolean getSystemAudioModeSetting() { 898377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, false); 899377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 900377dcbd53af4529c352d453424539b069909fce4Jungshik Jang 90179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 90279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Change ARC status into the given {@code enabled} status. 90379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 90479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @return {@code true} if ARC was in "Enabled" status 90579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 906a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 90779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang boolean setArcStatus(boolean enabled) { 908a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 9096b096d349b8ea879ee152a50df66427c919adabaJungshik Jang 9106b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled); 911a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang boolean oldStatus = mArcEstablished; 912a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 1. Enable/disable ARC circuit. 913757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim setAudioReturnChannel(enabled); 914a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 2. Notify arc status to audio service. 915a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang notifyArcStatusToAudioService(enabled); 916a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 3. Update arc status; 917a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang mArcEstablished = enabled; 918a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return oldStatus; 91979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 92079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 921757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim /** 922757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim * Switch hardware ARC circuit in the system. 923757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim */ 924757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim @ServiceThreadOnly 925757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim void setAudioReturnChannel(boolean enabled) { 926757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim assertRunOnServiceThread(); 927757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim HdmiDeviceInfo avr = getAvrDeviceInfo(); 928757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim if (avr != null) { 929757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim mService.setAudioReturnChannel(avr.getPortId(), enabled); 930757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim } 931757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim } 932757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim 9332ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim @ServiceThreadOnly 9342ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim private void updateArcFeatureStatus(int portId, boolean isConnected) { 9352ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim assertRunOnServiceThread(); 93637f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim HdmiPortInfo portInfo = mService.getPortInfo(portId); 93737f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (!portInfo.isArcSupported()) { 93837f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim return; 93937f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim } 940a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim HdmiDeviceInfo avr = getAvrDeviceInfo(); 941a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim if (avr == null) { 94237f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (isConnected) { 94337f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim // Update the status (since TV may not have seen AVR yet) so 94437f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim // that ARC can be initiated after discovery. 94537f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim mArcFeatureEnabled.put(portId, isConnected); 94637f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim } 947a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim return; 948a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim } 9492ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim // HEAC 2.4, HEACT 5-15 9502ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim // Should not activate ARC if +5V status is false. 95137f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (avr.getPortId() == portId) { 9525bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim changeArcFeatureEnabled(portId, isConnected); 9532ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim } 9542ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim } 9552ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim 9567b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim @ServiceThreadOnly 9577b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim boolean isConnected(int portId) { 9587b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim assertRunOnServiceThread(); 9597b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim return mService.isConnected(portId); 9607b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim } 9617b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim 962a858d221ff86c497e745222ea15bab141e337636Jungshik Jang private void notifyArcStatusToAudioService(boolean enabled) { 963a858d221ff86c497e745222ea15bab141e337636Jungshik Jang // Note that we don't set any name to ARC. 964a858d221ff86c497e745222ea15bab141e337636Jungshik Jang mService.getAudioManager().setWiredDeviceConnectionState( 965a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioSystem.DEVICE_OUT_HDMI_ARC, 96610804eb2818ab59b763a37b4f6151693c2ebba7bPaul McLean enabled ? 1 : 0, "", ""); 967a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 968a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 96979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 9705bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim * Returns true if ARC is currently established on a certain port. 97179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 972a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 9735bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim boolean isArcEstablished() { 974a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 9755bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcEstablished) { 9765bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim for (int i = 0; i < mArcFeatureEnabled.size(); i++) { 9775bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcFeatureEnabled.valueAt(i)) return true; 9785bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 9795bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 9805bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return false; 981a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 982a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 983a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 9845bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim void changeArcFeatureEnabled(int portId, boolean enabled) { 985a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 986a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 9875bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcFeatureEnabled.get(portId) != enabled) { 9885bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim mArcFeatureEnabled.put(portId, enabled); 989a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (enabled) { 990a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!mArcEstablished) { 991a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang startArcAction(true); 992a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 993a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } else { 994a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (mArcEstablished) { 995a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang startArcAction(false); 996a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 997a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 998a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 999a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1000a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 1001a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 10025bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim boolean isArcFeatureEnabled(int portId) { 1003a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 10045bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return mArcFeatureEnabled.get(portId); 1005a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1006a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 1007a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 1008339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void startArcAction(boolean enabled) { 1009a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 101061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = getAvrDeviceInfo(); 1011a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (info == null) { 1012339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Slog.w(TAG, "Failed to start arc action; No AVR device."); 1013a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1014a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1015339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!canStartArcUpdateAction(info.getLogicalAddress(), enabled)) { 1016339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Slog.w(TAG, "Failed to start arc action; ARC configuration check failed."); 1017339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (enabled && !isConnectedToArcPort(info.getPhysicalAddress())) { 1018339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT); 1019339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1020a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 1021a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1022a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 1023a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // Terminate opposite action and start action if not exist. 1024a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (enabled) { 1025a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang removeAction(RequestArcTerminationAction.class); 1026a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!hasAction(RequestArcInitiationAction.class)) { 1027a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang addAndStartAction(new RequestArcInitiationAction(this, info.getLogicalAddress())); 1028a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1029a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } else { 1030a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang removeAction(RequestArcInitiationAction.class); 1031a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!hasAction(RequestArcTerminationAction.class)) { 1032a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang addAndStartAction(new RequestArcTerminationAction(this, info.getLogicalAddress())); 1033a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 103479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 103579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 103679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1037339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang private boolean isDirectConnectAddress(int physicalAddress) { 1038339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return (physicalAddress & Constants.ROUTING_PATH_TOP_MASK) == physicalAddress; 1039339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1040339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 104179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 10428fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang synchronized (mLock) { 10438fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mSystemAudioMute = mute; 10448fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mSystemAudioVolume = volume; 1045b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang int maxVolume = mService.getAudioManager().getStreamMaxVolume( 1046b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.STREAM_MUSIC); 1047b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang mService.setAudioStatus(mute, 1048b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang VolumeControlAction.scaleToCustomVolume(volume, maxVolume)); 10492e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang displayOsd(HdmiControlManager.OSD_MESSAGE_AVR_VOLUME_CHANGED, 10502e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mute ? HdmiControlManager.AVR_VOLUME_MUTED : volume); 10518fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10528fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10538fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10548fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @ServiceThreadOnly 10558fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang void changeVolume(int curVolume, int delta, int maxVolume) { 10568fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 1057377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (delta == 0 || !isSystemAudioActivated()) { 10588fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10598fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10608fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10618fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int targetVolume = curVolume + delta; 10628fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int cecVolume = VolumeControlAction.scaleToCecVolume(targetVolume, maxVolume); 10638fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang synchronized (mLock) { 10648fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // If new volume is the same as current system audio volume, just ignore it. 10658fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Note that UNKNOWN_VOLUME is not in range of cec volume scale. 10668fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang if (cecVolume == mSystemAudioVolume) { 10678fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Update tv volume with system volume value. 10688fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mService.setAudioStatus(false, 10698fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang VolumeControlAction.scaleToCustomVolume(mSystemAudioVolume, maxVolume)); 10708fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10718fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10728fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10738fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10742e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang List<VolumeControlAction> actions = getActions(VolumeControlAction.class); 10752e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang if (actions.isEmpty()) { 10762e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang addAndStartAction(new VolumeControlAction(this, 10772e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getAvrDeviceInfo().getLogicalAddress(), delta > 0)); 10782e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } else { 10792e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang actions.get(0).handleVolumeChange(delta > 0); 10802e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 10818fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10828fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10838fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @ServiceThreadOnly 10848fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang void changeMute(boolean mute) { 10858fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 10866b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]:Change mute:%b", mute); 1087720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang synchronized (mLock) { 1088720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang if (mSystemAudioMute == mute) { 1089720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang HdmiLogger.debug("No need to change mute."); 1090720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang return; 1091720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang } 1092720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang } 1093377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (!isSystemAudioActivated()) { 10946b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]:System audio is not activated."); 10958fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10968fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10978fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10988fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Remove existing volume action. 10998fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang removeAction(VolumeControlAction.class); 11002e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang sendUserControlPressedAndReleased(getAvrDeviceInfo().getLogicalAddress(), 11010ab377917c4b2d4f754a03311f9b438a3ad37b82Jinsuk Kim HdmiCecKeycode.getMuteKey(mute)); 11028fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 11038fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 110479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1105a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 110679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleInitiateArc(HdmiCecMessage message) { 110779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 1108339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 1109339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!canStartArcUpdateAction(message.getSource(), true)) { 11107fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (getAvrDeviceInfo() == null) { 11117fa3a66470d2133796defd14a0600578758882acJinsuk Kim // AVR may not have been discovered yet. Delay the message processing. 11127fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.add(message); 11137fa3a66470d2133796defd14a0600578758882acJinsuk Kim return true; 11147fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1115339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); 1116339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!isConnectedToArcPort(message.getSource())) { 1117339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT); 1118339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1119339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return true; 1120339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1121339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 112279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // In case where <Initiate Arc> is started by <Request ARC Initiation> 112379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // need to clean up RequestArcInitiationAction. 112479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(RequestArcInitiationAction.class); 112579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 112679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang message.getSource(), true); 112779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 112879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 112979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 113079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1131339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang private boolean canStartArcUpdateAction(int avrAddress, boolean shouldCheckArcFeatureEnabled) { 1132339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 1133339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (avr != null 1134339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && (avrAddress == avr.getLogicalAddress()) 1135339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && isConnectedToArcPort(avr.getPhysicalAddress()) 1136339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && isDirectConnectAddress(avr.getPhysicalAddress())) { 1137339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (shouldCheckArcFeatureEnabled) { 11385bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return isArcFeatureEnabled(avr.getPortId()); 1139339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } else { 1140339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return true; 1141339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1142339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } else { 1143339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return false; 1144339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1145339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1146339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 114779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1148a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 114979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleTerminateArc(HdmiCecMessage message) { 115079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 11517e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim if (mService .isPowerStandbyOrTransient()) { 11527e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim setArcStatus(false); 11537e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim return true; 11547e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim } 11557e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // Do not check ARC configuration since the AVR might have been already removed. 11567e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // Clean up RequestArcTerminationAction in case <Terminate Arc> was started by 11577e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // <Request ARC Termination>. 115879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(RequestArcTerminationAction.class); 115979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 116079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang message.getSource(), false); 116179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 116279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 116379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 116479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 116579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1166a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 116779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { 116879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 116979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isMessageForSystemAudio(message)) { 1170ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim if (getAvrDeviceInfo() == null) { 1171ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim // AVR may not have been discovered yet. Delay the message processing. 1172ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim mDelayedMessageBuffer.add(message); 1173c21f63aa9514fb5f34e195fade88f8545d935992Donghyun Cho } else { 1174c21f63aa9514fb5f34e195fade88f8545d935992Donghyun Cho HdmiLogger.warning("Invalid <Set System Audio Mode> message:" + message); 1175c21f63aa9514fb5f34e195fade88f8545d935992Donghyun Cho mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); 1176ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim } 11774480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 117879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 1179c21f63aa9514fb5f34e195fade88f8545d935992Donghyun Cho removeAction(SystemAudioAutoInitiationAction.class); 118079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, 11817f0a1c54a837da7ebbb6f7eb56f44894e0df22c2Jungshik Jang message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message), null); 118279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 118379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 118479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 118579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 118679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1187a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 118879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { 118979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 119079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isMessageForSystemAudio(message)) { 11912e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Invalid <System Audio Mode Status> message:" + message); 11924480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Ignore this message. 11934480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 119479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 11957ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message), true); 119679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 119779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 119879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1199b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Seq #53 1200b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1201b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1202b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang protected boolean handleRecordTvScreen(HdmiCecMessage message) { 1203b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang List<OneTouchRecordAction> actions = getActions(OneTouchRecordAction.class); 1204b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!actions.isEmpty()) { 1205b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Assumes only one OneTouchRecordAction. 1206b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang OneTouchRecordAction action = actions.get(0); 1207b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (action.getRecorderAddress() != message.getSource()) { 120812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang announceOneTouchRecordResult( 1209326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang message.getSource(), 121012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlManager.ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS); 1211b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1212b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return super.handleRecordTvScreen(message); 1213b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1214b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1215b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang int recorderAddress = message.getSource(); 1216b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] recordSource = mService.invokeRecordRequestListener(recorderAddress); 12174480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int reason = startOneTouchRecord(recorderAddress, recordSource); 12184480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang if (reason != Constants.ABORT_NO_ERROR) { 12194480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang mService.maySendFeatureAbortCommand(message, reason); 12204480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 1221b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 1222b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1223b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1224e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang @Override 1225e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang protected boolean handleTimerClearedStatus(HdmiCecMessage message) { 1226e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang byte[] params = message.getParams(); 1227e9e0f070e34a612fb3bab5d97bdec1e266da4a20Jungshik Jang int timerClearedStatusData = params[0] & 0xFF; 1228326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(message.getSource(), timerClearedStatusData); 1229e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return true; 1230e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1231e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1232326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceOneTouchRecordResult(int recorderAddress, int result) { 1233326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeOneTouchRecordResult(recorderAddress, result); 123412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 123512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1236326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceTimerRecordingResult(int recorderAddress, int result) { 1237326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeTimerRecordingResult(recorderAddress, result); 123812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 123912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1240326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceClearTimerRecordingResult(int recorderAddress, int result) { 1241326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeClearTimerRecordingResult(recorderAddress, result); 1242faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang } 1243faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang 124479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean isMessageForSystemAudio(HdmiCecMessage message) { 12454480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return mService.isControlEnabled() 12464480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang && message.getSource() == Constants.ADDR_AUDIO_SYSTEM 1247473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang && (message.getDestination() == Constants.ADDR_TV 1248473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang || message.getDestination() == Constants.ADDR_BROADCAST) 1249473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang && getAvrDeviceInfo() != null; 125079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 125179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 125279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 125361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Add a new {@link HdmiDeviceInfo}. It returns old device info which has the same 125479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * logical address as new device info's. 125579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 125679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 125779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 125861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @param deviceInfo a new {@link HdmiDeviceInfo} to be added. 125961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@code null} if it is new device. Otherwise, returns old {@HdmiDeviceInfo} 126079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * that has the same logical address as new one has. 126179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1262a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 126361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) { 126479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 12658960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo oldDeviceInfo = getCecDeviceInfo(deviceInfo.getLogicalAddress()); 126679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (oldDeviceInfo != null) { 12678960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim removeDeviceInfo(deviceInfo.getId()); 126879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 12698960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mDeviceInfos.append(deviceInfo.getId(), deviceInfo); 1270fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 127179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return oldDeviceInfo; 127279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 127379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 127479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 127579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Remove a device info corresponding to the given {@code logicalAddress}. 127661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * It returns removed {@link HdmiDeviceInfo} if exists. 127779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 127879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 127979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 12808960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * @param id id of device to be removed 128161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return removed {@link HdmiDeviceInfo} it exists. Otherwise, returns {@code null} 128279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1283a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 12848960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim private HdmiDeviceInfo removeDeviceInfo(int id) { 128579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 12868960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo deviceInfo = mDeviceInfos.get(id); 128779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (deviceInfo != null) { 12888960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mDeviceInfos.remove(id); 128979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 1290fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 129179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return deviceInfo; 129279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 129379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 129479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 129561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Return a list of all {@link HdmiDeviceInfo}. 129679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 129779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 1298339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang * This is not thread-safe. For thread safety, call {@link #getSafeExternalInputsLocked} which 12998e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang * does not include local device. 130079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1301a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 13024b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim List<HdmiDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) { 130379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 13044b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim if (includeLocalDevice) { 1305fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang return HdmiUtils.sparseArrayToList(mDeviceInfos); 130679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } else { 130761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 130879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (int i = 0; i < mDeviceInfos.size(); ++i) { 130961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = mDeviceInfos.valueAt(i); 131079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isLocalDeviceAddress(info.getLogicalAddress())) { 131179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang infoList.add(info); 131279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 131379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 131479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return infoList; 131579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 131679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 131779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1318fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang /** 13199c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * Return external input devices. 1320fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang */ 1321ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> getSafeExternalInputsLocked() { 1322ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mSafeExternalInputs; 1323fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1324fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 1325a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1326fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang private void updateSafeDeviceInfoList() { 1327fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang assertRunOnServiceThread(); 132861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos); 132961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang List<HdmiDeviceInfo> externalInputs = getInputDevices(); 1330fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang synchronized (mLock) { 1331fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang mSafeAllDeviceInfos = copiedDevices; 13329c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mSafeExternalInputs = externalInputs; 13339c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13349c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13359c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 13369c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim /** 13379c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * Return a list of external cec input (source) devices. 13389c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * 13399c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * <p>Note that this effectively excludes non-source devices like system audio, 13409c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * secondary TV. 13419c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim */ 134261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private List<HdmiDeviceInfo> getInputDevices() { 134361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 13449c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim for (int i = 0; i < mDeviceInfos.size(); ++i) { 134561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = mDeviceInfos.valueAt(i); 13468960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (isLocalDeviceAddress(info.getLogicalAddress())) { 13479c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim continue; 13489c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13494fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (info.isSourceType() && !hideDevicesBehindLegacySwitch(info)) { 13509c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim infoList.add(info); 13519c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 1352fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 13539c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return infoList; 1354fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1355fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 13564fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // Check if we are hiding CEC devices connected to a legacy (non-CEC) switch. 13574fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // Returns true if the policy is set to true, and the device to check does not have 13584fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // a parent CEC device (which should be the CEC-enabled switch) in the list. 135961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private boolean hideDevicesBehindLegacySwitch(HdmiDeviceInfo info) { 13604fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return HdmiConfig.HIDE_DEVICES_BEHIND_LEGACY_SWITCH 13614fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim && !isConnectedToCecSwitch(info.getPhysicalAddress(), mCecSwitches); 13624fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13634fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 13644fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private static boolean isConnectedToCecSwitch(int path, Collection<Integer> switches) { 13654fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim for (int switchPath : switches) { 13664fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (isParentPath(switchPath, path)) { 13674fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return true; 13684fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13694fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13704fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return false; 13714fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13724fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 13734fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private static boolean isParentPath(int parentPath, int childPath) { 13744fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // (A000, AB00) (AB00, ABC0), (ABC0, ABCD) 13754fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // If child's last non-zero nibble is removed, the result equals to the parent. 13764fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim for (int i = 0; i <= 12; i += 4) { 13774fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int nibble = (childPath >> i) & 0xF; 13784fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (nibble != 0) { 13794fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int parentNibble = (parentPath >> i) & 0xF; 13804fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return parentNibble == 0 && (childPath >> i+4) == (parentPath >> i+4); 13814fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13824fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13834fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return false; 13844fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13854fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 138661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) { 138798d760e1c3123e6db8459f605d59a5689d56268cJinsuk Kim if (!hideDevicesBehindLegacySwitch(info)) { 138861daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mService.invokeDeviceEventListeners(info, status); 13894fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13904fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13914fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 139279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean isLocalDeviceAddress(int address) { 1393bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return mLocalDeviceAddresses.contains(address); 139479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 139579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1396e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang @ServiceThreadOnly 139761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getAvrDeviceInfo() { 1398e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang assertRunOnServiceThread(); 13998960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return getCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); 1400e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang } 1401e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang 140279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 140361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Return a {@link HdmiDeviceInfo} corresponding to the given {@code logicalAddress}. 140479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 14058960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * This is not thread-safe. For thread safety, call {@link #getSafeCecDeviceInfo(int)}. 140679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 1407339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang * @param logicalAddress logical address of the device to be retrieved 140861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. 140979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Returns null if no logical address matched 141079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1411a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 14128960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo getCecDeviceInfo(int logicalAddress) { 141379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 14148960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress)); 141579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 141679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1417e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang boolean hasSystemAudioDevice() { 1418e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return getSafeAvrDeviceInfo() != null; 1419e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang } 1420e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang 142161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getSafeAvrDeviceInfo() { 14228960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); 142379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 142479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 142579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 14268960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * Thread safe version of {@link #getCecDeviceInfo(int)}. 1427fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * 1428fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * @param logicalAddress logical address to be retrieved 142961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. 1430fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * Returns null if no logical address matched 1431fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang */ 14328960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) { 1433fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang synchronized (mLock) { 14348960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 14358960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) { 14368960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return info; 14378960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 14388960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 14398960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return null; 1440fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1441fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1442fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 1443bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim List<HdmiDeviceInfo> getSafeCecDevicesLocked() { 1444bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 1445bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 1446bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim if (isLocalDeviceAddress(info.getLogicalAddress())) { 1447bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim continue; 1448bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1449bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim infoList.add(info); 1450bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1451bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return infoList; 1452bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1453bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 1454fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang /** 14558f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang * Called when a device is newly added or a new device is detected or 14568f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang * existing device is updated. 145779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 145879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param info device info of a new device. 145979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1460a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 146161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang final void addCecDevice(HdmiDeviceInfo info) { 146279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 14636102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim HdmiDeviceInfo old = addDeviceInfo(info); 146413c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim if (info.getLogicalAddress() == mAddress) { 146513c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim // The addition of TV device itself should not be notified. 146613c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim return; 146713c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim } 14686102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim if (old == null) { 14696102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); 14706102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim } else if (!old.equals(info)) { 14714fcbf0b93e15e60eeb8b08a32d895de07c73cb1bJinsuk Kim invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 14724fcbf0b93e15e60eeb8b08a32d895de07c73cb1bJinsuk Kim invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); 14736102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim } 147479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 147579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 147679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 147779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Called when a device is removed or removal of device is detected. 147879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 147979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param address a logical address of a device to be removed 148079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1481a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 148279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final void removeCecDevice(int address) { 148379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 14848960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address)); 148526dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang 148679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecMessageCache.flushMessagesFrom(address); 148761daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 148879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 148979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 149026dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang @ServiceThreadOnly 149126dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang void handleRemoveActiveRoutingPath(int path) { 149226dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang assertRunOnServiceThread(); 149392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #23 149492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (isTailOfActivePath(path, getActivePath())) { 149592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 1496546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, true, null); 149792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 149892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 149992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 15005344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim /** 15015344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * Launch routing control process. 15025344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * 15035344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * @param routingForBootup true if routing control is initiated due to One Touch Play 15045344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * or TV power on 15055344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim */ 150692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @ServiceThreadOnly 15075344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim void launchRoutingControl(boolean routingForBootup) { 150892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim assertRunOnServiceThread(); 150992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #24 1510c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (getActivePortId() != Constants.INVALID_PORT_ID) { 15115344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim if (!routingForBootup && !isProhibitMode()) { 15125344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 15135344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim setActivePath(newPath); 1514546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, routingForBootup, null); 15155344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim } 151692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } else { 151792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int activePath = mService.getPhysicalAddress(); 151892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim setActivePath(activePath); 15192ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim if (!routingForBootup 15202ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim && !mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) { 15215344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(mAddress, 15225344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim activePath)); 15235344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim } 152492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 152592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 152692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 152779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 152861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Returns the {@link HdmiDeviceInfo} instance whose physical address matches 152979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * the given routing path. CEC devices use routing path for its physical address to 153079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * describe the hierarchy of the devices in the network. 153179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 153279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param path routing path or physical address 153361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null 153479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1535a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 153661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang final HdmiDeviceInfo getDeviceInfoByPath(int path) { 153779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 153861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : getDeviceInfoList(false)) { 153979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (info.getPhysicalAddress() == path) { 154079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return info; 154179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 154279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 154379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 154479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 154579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 154679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 15477640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * Returns the {@link HdmiDeviceInfo} instance whose physical address matches 15487640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * the given routing path. This is the version accessible safely from threads 15497640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * other than service thread. 15507640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * 15517640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * @param path routing path or physical address 15527640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null 15537640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim */ 15547640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim HdmiDeviceInfo getSafeDeviceInfoByPath(int path) { 15557640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim synchronized (mLock) { 15567640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 15577640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim if (info.getPhysicalAddress() == path) { 15587640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim return info; 15597640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15607640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15617640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim return null; 15627640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15637640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15647640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim 15657640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim /** 156679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Whether a device of the specified physical address and logical address exists 156779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * in a device info list. However, both are minimal condition and it could 156879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * be different device from the original one. 156979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 157079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param logicalAddress logical address of a device to be searched 157192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param physicalAddress physical address of a device to be searched 157279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @return true if exist; otherwise false 157379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1574a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 15757cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim boolean isInDeviceList(int logicalAddress, int physicalAddress) { 157679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 15778960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo device = getCecDeviceInfo(logicalAddress); 157879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device == null) { 157979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 158079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 158179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return device.getPhysicalAddress() == physicalAddress; 158279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 158379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 158479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1585a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 158692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim void onHotplug(int portId, boolean connected) { 158779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 158879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 15894fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (!connected) { 15904fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim removeCecSwitches(portId); 15914fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 159279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Tv device will have permanent HotplugDetectionAction. 159379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class); 159479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!hotplugActions.isEmpty()) { 159579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Note that hotplug action is single action running on a machine. 159679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // "pollAllDevicesNow" cleans up timer and start poll action immediately. 159724c23c1dd82870be4c09f3c5b6ae354de722de94Jungshik Jang // It covers seq #40, #43. 159879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang hotplugActions.get(0).pollAllDevicesNow(); 159979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 16002ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim updateArcFeatureStatus(portId, connected); 160160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1602160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 16034fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private void removeCecSwitches(int portId) { 16044fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim Iterator<Integer> it = mCecSwitches.iterator(); 16054fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim while (!it.hasNext()) { 16064fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int path = it.next(); 16074fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (pathToPortId(path) == portId) { 16084fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim it.remove(); 16094fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 16104fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 16114fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 16124fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 1613e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim @Override 1614160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @ServiceThreadOnly 1615160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim void setAutoDeviceOff(boolean enabled) { 1616160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim assertRunOnServiceThread(); 1617160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mAutoDeviceOff = enabled; 1618544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim } 1619544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim 1620544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim @ServiceThreadOnly 1621544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim void setAutoWakeup(boolean enabled) { 1622544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim assertRunOnServiceThread(); 1623544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoWakeup = enabled; 1624160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 162538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 162625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @ServiceThreadOnly 162725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean getAutoWakeup() { 162825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo assertRunOnServiceThread(); 162925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return mAutoWakeup; 163025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 163125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 163238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 163338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 16344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) { 163538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 16367fa3a66470d2133796defd14a0600578758882acJinsuk Kim mService.unregisterTvInputCallback(mTvInputCallback); 163738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Remove any repeated working actions. 163838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // HotplugDetectionAction will be reinstated during the wake up process. 163938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // HdmiControlService.onWakeUp() -> initializeLocalDevices() -> 164038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). 16414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(DeviceDiscoveryAction.class); 164238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo removeAction(HotplugDetectionAction.class); 1643410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang removeAction(PowerStatusMonitorAction.class); 1644faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang // Remove recording actions. 1645b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang removeAction(OneTouchRecordAction.class); 1646faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang removeAction(TimerRecordingAction.class); 16474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableSystemAudioIfExist(); 16494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableArcIfExist(); 1650a5445ce992a4e8ac5252975acedf3e5aec53867aJinsuk Kim 1651a5445ce992a4e8ac5252975acedf3e5aec53867aJinsuk Kim super.disableDevice(initiatedByCec, callback); 165249b47bbef8a8d27e9707d5d24848040519586a7aJinsuk Kim clearDeviceInfoList(); 16537cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim getActiveSource().invalidate(); 16547cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim setActivePath(Constants.INVALID_PHYSICAL_ADDRESS); 165538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 165638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 165738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 16584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 16594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableSystemAudioIfExist() { 16604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 16614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (getAvrDeviceInfo() == null) { 16624fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 16634fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16654fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Seq #31. 16664fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioActionFromAvr.class); 16674fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioActionFromTv.class); 16684fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioAutoInitiationAction.class); 16694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioStatusAction.class); 16704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(VolumeControlAction.class); 16714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 16744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableArcIfExist() { 16754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 167661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 16774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (avr == null) { 16784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 16794fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Seq #44. 16824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(RequestArcInitiationAction.class); 16835bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) { 16844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress())); 16854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 168838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 168938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 1690e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim protected void onStandby(boolean initiatedByCec, int standbyAction) { 169138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 169238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Seq #11 169338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (!mService.isControlEnabled()) { 169438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 169538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1696544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim if (!initiatedByCec && mAutoDeviceOff) { 169738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby( 1698c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress, Constants.ADDR_BROADCAST)); 169938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 170038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 170138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 17024d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 17034d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mService.isProhibitMode(); 17044d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1705b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim 1706b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim boolean isPowerStandbyOrTransient() { 1707b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim return mService.isPowerStandbyOrTransient(); 17088866c810b6778714da69ebc023ed432491caad92Jungshik Jang } 1709c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim 1710339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 1711c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim void displayOsd(int messageId) { 1712339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 1713339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang mService.displayOsd(messageId); 1714b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim } 1715b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 17162e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 17172e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 17182e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 17192e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mService.displayOsd(messageId, extra); 17202e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 17212e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 1722b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Seq #54 and #55 1723b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 17244480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int startOneTouchRecord(int recorderAddress, byte[] recordSource) { 1725b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1726b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!mService.isControlEnabled()) { 1727b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1728326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED); 17294480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NOT_IN_CORRECT_MODE; 1730b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1731b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1732b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecorder(recorderAddress)) { 1733b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1734326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1735326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 17364480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NOT_IN_CORRECT_MODE; 1737b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1738b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1739b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecordSource(recordSource)) { 1740b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 1741326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1742326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN); 1743d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return Constants.ABORT_CANNOT_PROVIDE_SOURCE; 1744b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1745b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1746b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang addAndStartAction(new OneTouchRecordAction(this, recorderAddress, recordSource)); 1747b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.i(TAG, "Start new [One Touch Record]-Target:" + recorderAddress + ", recordSource:" 1748b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang + Arrays.toString(recordSource)); 17494480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NO_ERROR; 1750b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1751b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1752b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1753b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void stopOneTouchRecord(int recorderAddress) { 1754b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1755b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!mService.isControlEnabled()) { 1756b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Can not stop one touch record. CEC control is disabled."); 1757326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED); 1758b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1759b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1760b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1761b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecorder(recorderAddress)) { 1762b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1763326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1764326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 1765b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1766b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1767b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1768b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Remove one touch record action so that other one touch record can be started. 1769b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang removeAction(OneTouchRecordAction.class); 1770b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildRecordOff(mAddress, recorderAddress)); 1771b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.i(TAG, "Stop [One Touch Record]-Target:" + recorderAddress); 1772b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1773b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1774b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private boolean checkRecorder(int recorderAddress) { 17758960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo device = getCecDeviceInfo(recorderAddress); 1776b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return (device != null) 1777b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang && (HdmiUtils.getTypeFromAddress(recorderAddress) 177861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang == HdmiDeviceInfo.DEVICE_RECORDER); 1779b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1780b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1781b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private boolean checkRecordSource(byte[] recordSource) { 1782b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return (recordSource != null) && HdmiRecordSources.checkRecordSource(recordSource); 1783b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1784b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1785b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1786b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) { 1787b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 178812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!mService.isControlEnabled()) { 178912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1790326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(recorderAddress, 1791326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED); 179212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 179312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1794b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 179512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!checkRecorder(recorderAddress)) { 179612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1797326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(recorderAddress, 1798e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); 179912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 180012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 180112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 180212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!checkTimerRecordingSource(sourceType, recordSource)) { 180312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 180412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang announceTimerRecordingResult( 1805326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang recorderAddress, 1806e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE); 180712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 180812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 180912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 181012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang addAndStartAction( 181112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang new TimerRecordingAction(this, recorderAddress, sourceType, recordSource)); 181212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.i(TAG, "Start [Timer Recording]-Target:" + recorderAddress + ", SourceType:" 181312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang + sourceType + ", RecordSource:" + Arrays.toString(recordSource)); 181412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 181512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 181612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private boolean checkTimerRecordingSource(int sourceType, byte[] recordSource) { 181712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return (recordSource != null) 181812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang && HdmiTimerRecordSources.checkTimerRecordSource(sourceType, recordSource); 1819b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1820b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1821b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1822b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) { 1823b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1824e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!mService.isControlEnabled()) { 1825e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1826326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, CLEAR_TIMER_STATUS_CEC_DISABLE); 1827e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1828e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1829e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1830e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!checkRecorder(recorderAddress)) { 1831e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1832326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1833326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION); 1834e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1835e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1836e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1837e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!checkTimerRecordingSource(sourceType, recordSource)) { 1838e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 1839326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1840326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1841e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1842e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1843e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1844e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang sendClearTimerMessage(recorderAddress, sourceType, recordSource); 1845e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1846e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1847326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang private void sendClearTimerMessage(final int recorderAddress, int sourceType, 1848326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang byte[] recordSource) { 1849e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang HdmiCecMessage message = null; 1850e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang switch (sourceType) { 1851e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_DIGITAL: 1852e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearDigitalTimer(mAddress, recorderAddress, 1853e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1854e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1855e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_ANALOGUE: 1856e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearAnalogueTimer(mAddress, recorderAddress, 1857e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1858e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1859e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_EXTERNAL: 1860e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearExternalTimer(mAddress, recorderAddress, 1861e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1862e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1863e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang default: 1864e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid source type:" + recorderAddress); 1865326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1866326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1867e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1868b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1869e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1870e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mService.sendCecCommand(message, new SendMessageCallback() { 1871e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang @Override 1872e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang public void onSendCompleted(int error) { 1873e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (error != Constants.SEND_RESULT_SUCCESS) { 1874326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1875faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1876e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1877e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1878e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang }); 1879b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1880410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1881410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) { 18828960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); 1883410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (info == null) { 1884410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress); 1885410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return; 1886410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1887410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1888410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (info.getDevicePowerStatus() == newPowerStatus) { 1889410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return; 1890410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1891410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1892410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus); 1893410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // addDeviceInfo replaces old device info with new one if exists. 1894410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addDeviceInfo(newInfo); 1895410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 189661daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(newInfo, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE); 1897410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1898959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1899959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1900184b124ec22a796327642e3546d366179e693f07Yuncheol Heo protected boolean handleMenuStatus(HdmiCecMessage message) { 1901184b124ec22a796327642e3546d366179e693f07Yuncheol Heo // Do nothing and just return true not to prevent from responding <Feature Abort>. 1902184b124ec22a796327642e3546d366179e693f07Yuncheol Heo return true; 1903184b124ec22a796327642e3546d366179e693f07Yuncheol Heo } 1904184b124ec22a796327642e3546d366179e693f07Yuncheol Heo 1905184b124ec22a796327642e3546d366179e693f07Yuncheol Heo @Override 1906d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim protected void sendStandby(int deviceId) { 1907d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiDeviceInfo targetDevice = mDeviceInfos.get(deviceId); 1908d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (targetDevice == null) { 1909d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1910d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1911d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim int targetAddress = targetDevice.getLogicalAddress(); 1912d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress)); 1913d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1914d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 19157fa3a66470d2133796defd14a0600578758882acJinsuk Kim @ServiceThreadOnly 19167fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processAllDelayedMessages() { 19177fa3a66470d2133796defd14a0600578758882acJinsuk Kim assertRunOnServiceThread(); 19187fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.processAllMessages(); 19197fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 19207fa3a66470d2133796defd14a0600578758882acJinsuk Kim 19217fa3a66470d2133796defd14a0600578758882acJinsuk Kim @ServiceThreadOnly 19227fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processDelayedMessages(int address) { 19237fa3a66470d2133796defd14a0600578758882acJinsuk Kim assertRunOnServiceThread(); 19247fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.processMessagesForDevice(address); 19257fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 19267fa3a66470d2133796defd14a0600578758882acJinsuk Kim 19276e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 19286e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim void processDelayedActiveSource(int address) { 19296e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 19306e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mDelayedMessageBuffer.processActiveSource(address); 19316e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 19326e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1933d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1934959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(final IndentingPrintWriter pw) { 1935959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo super.dump(pw); 1936959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mArcEstablished: " + mArcEstablished); 1937959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mArcFeatureEnabled: " + mArcFeatureEnabled); 1938959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSystemAudioActivated: " + mSystemAudioActivated); 1939959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSystemAudioMute: " + mSystemAudioMute); 1940959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAutoDeviceOff: " + mAutoDeviceOff); 1941959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAutoWakeup: " + mAutoWakeup); 1942959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSkipRoutingControl: " + mSkipRoutingControl); 1943cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim pw.println("mPrevPortId: " + mPrevPortId); 19444b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.println("CEC devices:"); 19454b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.increaseIndent(); 19464b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 19474b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.println(info); 19484b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim } 19494b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.decreaseIndent(); 1950959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 19512918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim} 1952