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); 1417fa3a66470d2133796defd14a0600578758882acJinsuk Kim HdmiDeviceInfo info = tvInfo.getHdmiDeviceInfo(); 1426e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim if (info == null) return; 1436e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim addTvInput(inputId, info.getId()); 1446e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim if (info.isCecDevice()) { 1456e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim processDelayedActiveSource(info.getLogicalAddress()); 1467fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1477fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1486e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1496e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @Override 1506e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim public void onInputRemoved(String inputId) { 1516e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim removeTvInput(inputId); 1526e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1537fa3a66470d2133796defd14a0600578758882acJinsuk Kim }; 1547fa3a66470d2133796defd14a0600578758882acJinsuk Kim 1556e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // Keeps the mapping (TV input ID, HDMI device ID) to keep track of the TV inputs ready to 1566e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // accept input switching request from HDMI devices. Requests for which the corresponding 1576e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // input ID is not yet registered by TV input framework need to be buffered for delayed 1586e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim // processing. 1596e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private final HashMap<String, Integer> mTvInputs = new HashMap<>(); 1606e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1616e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1626e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private void addTvInput(String inputId, int deviceId) { 1636e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1646e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.put(inputId, deviceId); 1656e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1666e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1676e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1686e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim private void removeTvInput(String inputId) { 1696e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1706e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.remove(inputId); 1716e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1726e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1736e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @Override 1746e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 1756e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim protected boolean isInputReady(int deviceId) { 1766e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 1776e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim return mTvInputs.containsValue(deviceId); 1786e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 1796e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang HdmiCecLocalDeviceTv(HdmiControlService service) { 18161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang super(service, HdmiDeviceInfo.DEVICE_TV); 182c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mPrevPortId = Constants.INVALID_PORT_ID; 183544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoDeviceOff = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED, 184544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim true); 185544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoWakeup = mService.readBooleanSetting(Global.HDMI_CONTROL_AUTO_WAKEUP_ENABLED, true); 18625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); 1878b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang } 1882918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1898b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang @Override 190a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 191fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo protected void onAddressAllocated(int logicalAddress, int reason) { 19279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 1935bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim List<HdmiPortInfo> ports = mService.getPortInfo(); 1945bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim for (HdmiPortInfo port : ports) { 1955bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim mArcFeatureEnabled.put(port.getId(), port.isArcSupported()); 1965bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 1977fa3a66470d2133796defd14a0600578758882acJinsuk Kim mService.registerTvInputCallback(mTvInputCallback); 1983ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 1993ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress, mService.getPhysicalAddress(), mDeviceType)); 2003ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 2013ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress, mService.getVendorId())); 2024fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim mCecSwitches.add(mService.getPhysicalAddress()); // TV is a CEC switch too. 2036e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mTvInputs.clear(); 204d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE); 205fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC && 206fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo reason != HdmiControlService.INITIATED_BY_BOOT_UP); 207bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim mLocalDeviceAddresses = initLocalDeviceAddresses(); 20860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang launchDeviceDiscovery(); 2096f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang } 2106f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang 211bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 212bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim @ServiceThreadOnly 213bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim private List<Integer> initLocalDeviceAddresses() { 214bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim assertRunOnServiceThread(); 215bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim List<Integer> addresses = new ArrayList<>(); 216bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { 217bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim addresses.add(device.getDeviceInfo().getLogicalAddress()); 218bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 219bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return Collections.unmodifiableList(addresses); 220bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 221bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 222af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim @Override 223af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected int getPreferredAddress() { 224d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return Constants.ADDR_TV; 225af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim } 226af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 227af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim @Override 228af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected void setPreferredAddress(int addr) { 229d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim Slog.w(TAG, "Preferred addres will not be stored for TV"); 230af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim } 231af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 23225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @Override 23325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @ServiceThreadOnly 23425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean dispatchMessage(HdmiCecMessage message) { 23525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo assertRunOnServiceThread(); 23625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo if (mService.isPowerStandby() && mStandbyHandler.handleCommand(message)) { 23725c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return true; 23825c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 23925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return super.onMessage(message); 24025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 24125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 242a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim /** 243a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * Performs the action 'device select', or 'one touch play' initiated by TV. 244a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * 2458960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * @param id id of HDMI device to select 246a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim * @param callback callback object to report the result with 247a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim */ 248a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 2498960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim void deviceSelect(int id, IHdmiControlCallback callback) { 25079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 2518960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo targetDevice = mDeviceInfos.get(id); 2528960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (targetDevice == null) { 2538960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); 2548960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return; 2558960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 2568960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim int targetAddress = targetDevice.getLogicalAddress(); 25758500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim ActiveSource active = getActiveSource(); 2586b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara if (targetDevice.getDevicePowerStatus() == HdmiControlManager.POWER_STATUS_ON 2596b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara && active.isValid() 2606b2a6177aad44466794a9262a4f2f2c209a3f2e5Yu.Ishihara && targetAddress == active.logicalAddress) { 26158500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 26258500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim return; 26358500f43ecbed3f92d7c077fb6ce396252cd00eaJinsuk Kim } 264c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (targetAddress == Constants.ADDR_INTERNAL) { 2655ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim handleSelectInternalSource(); 2665ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim // Switching to internal source is always successful even when CEC control is disabled. 26772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(targetAddress, mService.getPhysicalAddress()); 2687e74206693f4ee93afb902d5b3446e2384f2a13dJinsuk Kim setActivePath(mService.getPhysicalAddress()); 2695ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 2708333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return; 2718333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 27209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isControlEnabled()) { 2738960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim setActiveSource(targetDevice); 27409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 27509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim return; 27609ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 27779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(DeviceSelectAction.class); 27879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(new DeviceSelectAction(this, targetDevice, callback)); 279a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 280a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 2818333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 2825ad57168da6456e8e4935aaa8512a7f77b74b0a1Jinsuk Kim private void handleSelectInternalSource() { 2838333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 2848333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #18 28572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mService.isControlEnabled() && mActiveSource.logicalAddress != mAddress) { 2868333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim updateActiveSource(mAddress, mService.getPhysicalAddress()); 287d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim if (mSkipRoutingControl) { 288d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = false; 289d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim return; 290d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim } 2918333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim HdmiCecMessage activeSource = HdmiCecMessageBuilder.buildActiveSource( 2928333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mAddress, mService.getPhysicalAddress()); 2938333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mService.sendCecCommand(activeSource); 2948333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 2958333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 2968333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 2978333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 29872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveSource(int logicalAddress, int physicalAddress) { 29972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim assertRunOnServiceThread(); 30072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim updateActiveSource(ActiveSource.of(logicalAddress, physicalAddress)); 30172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 30272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 30372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @ServiceThreadOnly 30472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveSource(ActiveSource newActive) { 3058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 3068333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #14 30772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mActiveSource.equals(newActive)) { 3088333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return; 3098333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 31072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(newActive); 31172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress = newActive.logicalAddress; 3128960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (getCecDeviceInfo(logicalAddress) != null && logicalAddress != mAddress) { 31372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mService.pathToPortId(newActive.physicalAddress) == getActivePortId()) { 3148333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim setPrevPortId(getActivePortId()); 3158333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Show the OSD banner related to the new active source device. 3178333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } else { 3188333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: If displayed, remove the OSD banner related to the previous 3198333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // active source device. 3208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3218333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3228333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3232b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim int getPortId(int physicalAddress) { 3242b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim return mService.pathToPortId(physicalAddress); 3252b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim } 3262b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim 327a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 3288333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * Returns the previous port id kept to handle input switching on <Inactive Source>. 3298333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim */ 3308333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim int getPrevPortId() { 3318333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 3328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return mPrevPortId; 3338333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3348333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3358333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim /** 3378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * Sets the previous port id. INVALID_PORT_ID invalidates it, hence no actions will be 3388333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim * taken for <Inactive Source>. 339a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 3408333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void setPrevPortId(int portId) { 3418333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 3428333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mPrevPortId = portId; 3438333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3448333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3458333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 346a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 34772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void updateActiveInput(int path, boolean notifyInputChange) { 348a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim assertRunOnServiceThread(); 3498333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #15 35072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActivePath(path); 35172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim // TODO: Handle PAP/PIP case. 35272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim // Show OSD port change banner 35372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (notifyInputChange) { 35472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource activeSource = getActiveSource(); 3558960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(activeSource.logicalAddress); 35672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (info == null) { 3576ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim info = mService.getDeviceInfoByPort(getActivePortId()); 3586ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim if (info == null) { 3596ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim // No CEC/MHL device is present at the port. Attempt to switch to 3606ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim // the hardware port itself for non-CEC devices that may be connected. 3616ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim info = new HdmiDeviceInfo(path, getActivePortId()); 3626ad7cbde22fe9752082ce01c9b9be213b07afefcJinsuk Kim } 36372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 36472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mService.invokeInputChangeListener(info); 36572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 3668333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3678333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3688333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3698333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void doManualPortSwitching(int portId, IHdmiControlCallback callback) { 3708333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 3718333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #20 37209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isValidPortId(portId)) { 373c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 374a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim return; 375a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 37672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (portId == getActivePortId()) { 37772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS); 37872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return; 37972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 38043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim mActiveSource.invalidate(); 38109ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim if (!mService.isControlEnabled()) { 38209ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim setActivePortId(portId); 38309ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 38409ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim return; 38509ffc846af78f949d2847003db9f793bfb5eefaaJinsuk Kim } 3861f8d1c576f06ed63c21d175fb0c86db596f59353Jinsuk Kim int oldPath = getActivePortId() != Constants.INVALID_PORT_ID 3871f8d1c576f06ed63c21d175fb0c86db596f59353Jinsuk Kim ? mService.portIdToPath(getActivePortId()) : getDeviceInfo().getPhysicalAddress(); 388d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim setActivePath(oldPath); 389d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim if (mSkipRoutingControl) { 390d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim mSkipRoutingControl = false; 391d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim return; 392d530719b169c8a10dccaefc413261e1b127cee63Jinsuk Kim } 393a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim int newPath = mService.portIdToPath(portId); 394546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(oldPath, newPath, true, callback); 395546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim } 396546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim 397546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim @ServiceThreadOnly 398546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim void startRoutingControl(int oldPath, int newPath, boolean queryDevicePowerStatus, 399546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim IHdmiControlCallback callback) { 400546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim assertRunOnServiceThread(); 401546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim if (oldPath == newPath) { 402546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim return; 403546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim } 404a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecMessage routingChange = 405a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim HdmiCecMessageBuilder.buildRoutingChange(mAddress, oldPath, newPath); 406a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim mService.sendCecCommand(routingChange); 40772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim removeAction(RoutingControlAction.class); 408546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim addAndStartAction( 409546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim new RoutingControlAction(this, newPath, queryDevicePowerStatus, callback)); 410a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 411a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 412f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang @ServiceThreadOnly 413cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim int getPowerStatus() { 414f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang assertRunOnServiceThread(); 415cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim return mService.getPowerStatus(); 416cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim } 417cae6627702a3bae3121f0ebbb9c8069e77f81cc7Jinsuk Kim 418a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 419a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Sends key to a target CEC device. 420a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * 421fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * @param keyCode key code to send. Defined in {@link android.view.KeyEvent}. 422c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * @param isPressed true if this is key press event 423a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 424c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim @Override 425a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 426c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim protected void sendKeyEvent(int keyCode, boolean isPressed) { 427a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim assertRunOnServiceThread(); 428b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo if (!HdmiCecKeycode.isSupportedKeycode(keyCode)) { 429b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo Slog.w(TAG, "Unsupported key: " + keyCode); 430b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo return; 431b64c2ba05bf64bb8015444fdcd706fa3238cb96cDongil Seo } 432a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim List<SendKeyAction> action = getActions(SendKeyAction.class); 433454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim int logicalAddress = findKeyReceiverAddress(); 434454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim if (logicalAddress == mAddress) { 435454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim Slog.w(TAG, "Discard key event to itself :" + keyCode + " pressed:" + isPressed); 436454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim return; 437454fab52195f86d08d0b7626ed170af113e44695Jinsuk Kim } 438a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim if (!action.isEmpty()) { 439a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim action.get(0).processKeyEvent(keyCode, isPressed); 440a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } else { 4417543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (isPressed) { 4427543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (logicalAddress != Constants.ADDR_INVALID) { 4437543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode)); 4447543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return; 4457543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 446a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 4477543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed); 448a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 449a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 450a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 4517543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim private int findKeyReceiverAddress() { 4527543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (getActiveSource().isValid()) { 4537543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return getActiveSource().logicalAddress; 4547543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4557543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim HdmiDeviceInfo info = getDeviceInfoByPath(getActivePath()); 4567543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim if (info != null) { 4577543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return info.getLogicalAddress(); 4587543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4597543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim return Constants.ADDR_INVALID; 4607543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim } 4617543497f8a8a8ba15edd622061f5d30dfbf6655aJinsuk Kim 462a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim private static void invokeCallback(IHdmiControlCallback callback, int result) { 4634893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim if (callback == null) { 4644893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim return; 4654893c7efde52411ad051ef5c20251439f4098eacJinsuk Kim } 466a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim try { 467a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim callback.onComplete(result); 468a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } catch (RemoteException e) { 469a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim Slog.e(TAG, "Invoking callback failed:" + e); 470a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 471a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim } 472a6ce7708d6124224399241503fadcafe0c4684d4Jinsuk Kim 473092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang @Override 474a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 4758333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleActiveSource(HdmiCecMessage message) { 4768333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 47772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress = message.getSource(); 47872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); 479bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); 480bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim if (info == null) { 4817fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (!handleNewDeviceAtTheTailOfActivePath(physicalAddress)) { 482cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim HdmiLogger.debug("Device info %X not found; buffering the command", logicalAddress); 4837fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.add(message); 4847fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 4856e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } else if (!isInputReady(info.getId())) { 4866e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim HdmiLogger.debug("Input not ready for device: %X; buffering the command", info.getId()); 4876e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mDelayedMessageBuffer.add(message); 48892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } else { 4897cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim updateDevicePowerStatus(logicalAddress, HdmiControlManager.POWER_STATUS_ON); 49072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress); 491bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType()); 49292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 4938333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 4948333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 4958333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 4968333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 4978333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 4988333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleInactiveSource(HdmiCecMessage message) { 4998333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 5008333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #10 5018333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5028333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Ignore <Inactive Source> from non-active source device. 50372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (getActiveSource().logicalAddress != message.getSource()) { 5048333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5064d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (isProhibitMode()) { 5078333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5088333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5098333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim int portId = getPrevPortId(); 510c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (portId != Constants.INVALID_PORT_ID) { 5118333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Do this only if TV is not showing multiview like PIP/PAP. 5128333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5138960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo inactiveSource = getCecDeviceInfo(message.getSource()); 5148333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim if (inactiveSource == null) { 5158333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5178333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim if (mService.pathToPortId(inactiveSource.getPhysicalAddress()) == portId) { 5188333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5198333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // TODO: Switch the TV freeze mode off 5218333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5228333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim doManualPortSwitching(portId, null); 523c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim setPrevPortId(Constants.INVALID_PORT_ID); 524cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim } else { 525cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // No HDMI port to switch to was found. Notify the input change listers to 526cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim // switch to the lastly shown internal input. 527cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim mActiveSource.invalidate(); 528cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim setActivePath(Constants.INVALID_PHYSICAL_ADDRESS); 529cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim mService.invokeInputChangeListener(HdmiDeviceInfo.INACTIVE_DEVICE); 5308333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5318333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5338333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5348333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 5358333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 5368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleRequestActiveSource(HdmiCecMessage message) { 5378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim assertRunOnServiceThread(); 5388333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim // Seq #19 53972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (mAddress == getActiveSource().logicalAddress) { 5408333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mService.sendCecCommand( 54192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim HdmiCecMessageBuilder.buildActiveSource(mAddress, getActivePath())); 5428333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5438333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return true; 5448333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 5458333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 5468333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @Override 5478333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 548092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetMenuLanguage(HdmiCecMessage message) { 54979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 550f67113f7abd536cc3eb888344bf925762aa5278eJungshik Jang if (!broadcastMenuLanguage(mService.getLanguage())) { 551092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Failed to respond to <Get Menu Language>: " + message.toString()); 552092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 553092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 554092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 555092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 5561ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo @ServiceThreadOnly 5571ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo boolean broadcastMenuLanguage(String language) { 5581ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo assertRunOnServiceThread(); 5591ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo HdmiCecMessage command = HdmiCecMessageBuilder.buildSetMenuLanguageCommand( 5601ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mAddress, language); 5611ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo if (command != null) { 5621ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo mService.sendCecCommand(command); 5631ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo return true; 5641ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 5651ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo return false; 5661ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo } 5671ca0a43251a31bb1b4253dc404316cc4b840f497Terry Heo 56860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang @Override 569a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 57060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { 57179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5724fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int path = HdmiUtils.twoBytesToInt(message.getParams()); 5734fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int address = message.getSource(); 574bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim int type = message.getParams()[2]; 5754fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 576bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (updateCecSwitchInfo(address, type, path)) return true; 5774fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 578092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // Ignore if [Device Discovery Action] is going on. 57979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (hasAction(DeviceDiscoveryAction.class)) { 5804fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim Slog.i(TAG, "Ignored while Device Discovery Action is in progress: " + message); 581092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 582092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 583092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 5844b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim if (!isInDeviceList(address, path)) { 5858f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang handleNewDeviceAtTheTailOfActivePath(path); 58692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 5877cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim 5887cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim // Add the device ahead with default information to handle <Active Source> 5897cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim // promptly, rather than waiting till the new device action is finished. 5907cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo(address, path, getPortId(path), type, 5917cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim Constants.UNKNOWN_VENDOR_ID, HdmiUtils.getDefaultDeviceName(address)); 5927cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim addCecDevice(deviceInfo); 593bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim startNewDeviceAction(ActiveSource.of(address, path), type); 59492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; 59592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 59692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 5974480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 5984480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleReportPowerStatus(HdmiCecMessage command) { 5994480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int newStatus = command.getParams()[0] & 0xFF; 6004480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang updateDevicePowerStatus(command.getSource(), newStatus); 6014480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6024480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6034480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6044480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 6054480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleTimerStatus(HdmiCecMessage message) { 6064480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Do nothing. 6074480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6084480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6094480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6104480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang @Override 6114480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleRecordStatus(HdmiCecMessage message) { 6124480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Do nothing. 6134480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 6144480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6154480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 616bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim boolean updateCecSwitchInfo(int address, int type, int path) { 617bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (address == Constants.ADDR_UNREGISTERED 618bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim && type == HdmiDeviceInfo.DEVICE_PURE_CEC_SWITCH) { 619bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim mCecSwitches.add(path); 620bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim updateSafeDeviceInfoList(); 621bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim return true; // Pure switch does not need further processing. Return here. 622bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 623bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim if (type == HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM) { 624bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim mCecSwitches.add(path); 625bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 626bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim return false; 627bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim } 628bcfa0677d4b015457b73b1147c96e4ad2946b2beJinsuk Kim 629bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim void startNewDeviceAction(ActiveSource activeSource, int deviceType) { 63097affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang for (NewDeviceAction action : getActions(NewDeviceAction.class)) { 63197affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // If there is new device action which has the same logical address and path 63297affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // ignore new request. 63397affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // NewDeviceAction is created whenever it receives <Report Physical Address>. 63497affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // And there is a chance starting NewDeviceAction for the same source. 63597affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // Usually, new device sends <Report Physical Address> when it's plugged 63697affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // in. However, TV can detect a new device from HotPlugDetectionAction, 63797affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // which sends <Give Physical Address> to the source for newly detected 63897affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang // device. 63972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (action.isActionOf(activeSource)) { 64097affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang return; 64197affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 64297affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 64397affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang 64472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, 645bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim activeSource.physicalAddress, deviceType)); 64697affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang } 64797affee67b6d88da40af41b36f02ecb2b823daffJungshik Jang 6487fa3a66470d2133796defd14a0600578758882acJinsuk Kim private boolean handleNewDeviceAtTheTailOfActivePath(int path) { 64992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #22 65092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (isTailOfActivePath(path, getActivePath())) { 65192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 6527c3a95633d307c4be30c9dbbf1071063aa7a3c64Jinsuk Kim setActivePath(newPath); 653546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, false, null); 6547fa3a66470d2133796defd14a0600578758882acJinsuk Kim return true; 65592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 6567fa3a66470d2133796defd14a0600578758882acJinsuk Kim return false; 65792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 658092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 65992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim /** 66092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * Whether the given path is located in the tail of current active path. 66192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * 66292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param path to be tested 66392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param activePath current active path 66492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @return true if the given path is located in the tail of current active path; otherwise, 66592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * false 66692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim */ 66792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim static boolean isTailOfActivePath(int path, int activePath) { 66892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // If active routing path is internal source, return false. 66992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (activePath == 0) { 67092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 67192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 67292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim for (int i = 12; i >= 0; i -= 4) { 67392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int curActivePath = (activePath >> i) & 0xF; 67492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (curActivePath == 0) { 67592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return true; 67692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } else { 67792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int curPath = (path >> i) & 0xF; 67892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (curPath != curActivePath) { 67992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 68092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 68192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 68292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 68392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 68492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 68592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 68692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @Override 68792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @ServiceThreadOnly 68892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim protected boolean handleRoutingChange(HdmiCecMessage message) { 68992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim assertRunOnServiceThread(); 69092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #21 69192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim byte[] params = message.getParams(); 69292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int currentPath = HdmiUtils.twoBytesToInt(params); 69392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (HdmiUtils.isAffectingActiveRoutingPath(getActivePath(), currentPath)) { 69443c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim mActiveSource.invalidate(); 69592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim removeAction(RoutingControlAction.class); 69643c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim int newPath = HdmiUtils.twoBytesToInt(params, 2); 69704fd28046acc2ac74339ed94cec76a0bfda846f7Jinsuk Kim addAndStartAction(new RoutingControlAction(this, newPath, true, null)); 69892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 699092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 700092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 7010a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim 7020a3316bcfdac9f5f40d1349d97d10329c70f7e30Jinsuk Kim @Override 703a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 7048fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang protected boolean handleReportAudioStatus(HdmiCecMessage message) { 7058fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 7068fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 7078fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang byte params[] = message.getParams(); 7088fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int mute = params[0] & 0x80; 7098fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int volume = params[0] & 0x7F; 7108fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang setAudioStatus(mute == 0x80, volume); 7118fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return true; 7128fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 7138fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 71438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 71538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 71638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleTextViewOn(HdmiCecMessage message) { 71738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 718544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim if (mService.isPowerStandbyOrTransient() && mAutoWakeup) { 71938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.wakeUp(); 72038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 72138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 72238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 72338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 72438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 72538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 72638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleImageViewOn(HdmiCecMessage message) { 72738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 72838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Currently, it's the same as <Text View On>. 72938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleTextViewOn(message); 73038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 73138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 7328f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang @Override 7338f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang @ServiceThreadOnly 7348f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang protected boolean handleSetOsdName(HdmiCecMessage message) { 7358f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang int source = message.getSource(); 7368960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo deviceInfo = getCecDeviceInfo(source); 7378f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang // If the device is not in device list, ignore it. 7388f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang if (deviceInfo == null) { 7398f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.e(TAG, "No source device info for <Set Osd Name>." + message); 7408f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7418f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7428f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang String osdName = null; 7438f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang try { 7448f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang osdName = new String(message.getParams(), "US-ASCII"); 7458f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } catch (UnsupportedEncodingException e) { 7468f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.e(TAG, "Invalid <Set Osd Name> request:" + message, e); 7478f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7488f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7498f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 7508f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang if (deviceInfo.getDisplayName().equals(osdName)) { 7518f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang Slog.i(TAG, "Ignore incoming <Set Osd Name> having same osd name:" + message); 7528f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7538f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7548f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 75561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang addCecDevice(new HdmiDeviceInfo(deviceInfo.getLogicalAddress(), 7562b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim deviceInfo.getPhysicalAddress(), deviceInfo.getPortId(), 7572b152015ff94f20b9ec3ef284fb83105f8b3c831Jinsuk Kim deviceInfo.getDeviceType(), deviceInfo.getVendorId(), osdName)); 7588f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 7598f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 7608f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 761a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 76260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang private void launchDeviceDiscovery() { 76379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 76479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang clearDeviceInfoList(); 76579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang DeviceDiscoveryAction action = new DeviceDiscoveryAction(this, 76660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang new DeviceDiscoveryCallback() { 76760cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang @Override 76861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang public void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos) { 76961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : deviceInfos) { 77079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addCecDevice(info); 77160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 77260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 77360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // Since we removed all devices when it's start and 77460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // device discovery action does not poll local devices, 77560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang // we should put device info of local device manually here 77660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { 77779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addCecDevice(device.getDeviceInfo()); 77860cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 77960cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 78079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(new HotplugDetectionAction(HdmiCecLocalDeviceTv.this)); 781410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addAndStartAction(new PowerStatusMonitorAction(HdmiCecLocalDeviceTv.this)); 782187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang 783187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // If there is AVR, initiate System Audio Auto initiation action, 784187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // which turns on and off system audio according to last system 785187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang // audio setting. 786339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 787339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (avr != null) { 788339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang onNewAvrAdded(avr); 789951e3e42f5943d90b74d9feb9fbc224afa59ed31Wally Yau } else { 790951e3e42f5943d90b74d9feb9fbc224afa59ed31Wally Yau setSystemAudioMode(false, true); 791187d01765b935d07936f74343b4f4af590c239a1Jungshik Jang } 79260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 79360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang }); 79479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 79579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 79679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 797339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 798339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void onNewAvrAdded(HdmiDeviceInfo avr) { 799339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 800ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim if (getSystemAudioModeSetting() && !isSystemAudioActivated()) { 8017fa3a66470d2133796defd14a0600578758882acJinsuk Kim addAndStartAction(new SystemAudioAutoInitiationAction(this, avr.getLogicalAddress())); 8027fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 8035bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (isArcFeatureEnabled(avr.getPortId()) 8045bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim && !hasAction(SetArcTransmissionStateAction.class)) { 805339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang startArcAction(true); 806339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 807339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 808339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 80979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Clear all device info. 810a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 81179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private void clearDeviceInfoList() { 81279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 81361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : mSafeExternalInputs) { 81461daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 81549b47bbef8a8d27e9707d5d24848040519586a7aJinsuk Kim } 81679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mDeviceInfos.clear(); 817fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 81879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 81979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 820a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 821c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo // Seq #32 822ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang void changeSystemAudioMode(boolean enabled, IHdmiControlCallback callback) { 823ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang assertRunOnServiceThread(); 824c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo if (!mService.isControlEnabled() || hasAction(DeviceDiscoveryAction.class)) { 825c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo setSystemAudioMode(false, true); 826c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo invokeCallback(callback, HdmiControlManager.RESULT_INCORRECT_MODE); 827c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo return; 828c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo } 82961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 830ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang if (avr == null) { 831c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo setSystemAudioMode(false, true); 832d05f67f9721e1f9194a1f57cf7481b4be65366b3Yuncheol Heo invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE); 833ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang return; 834ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 835ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 836ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang addAndStartAction( 837ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang new SystemAudioActionFromTv(this, avr.getLogicalAddress(), enabled, callback)); 838ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang } 839ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang 840ca5be9a8fbc91daece39c851ca3f09d60b24b870Jungshik Jang // # Seq 25 8417ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim void setSystemAudioMode(boolean on, boolean updateSetting) { 8422e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on); 843473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang 844377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (updateSetting) { 845377dcbd53af4529c352d453424539b069909fce4Jungshik Jang mService.writeBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, on); 846377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 847377dcbd53af4529c352d453424539b069909fce4Jungshik Jang updateAudioManagerForSystemAudio(on); 84879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 849377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (mSystemAudioActivated != on) { 850377dcbd53af4529c352d453424539b069909fce4Jungshik Jang mSystemAudioActivated = on; 851ea67c183fe5511ad99aeaae1a32b5245bd020e36Jungshik Jang mService.announceSystemAudioModeChange(on); 85279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 85379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 85479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 85579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 856377dcbd53af4529c352d453424539b069909fce4Jungshik Jang private void updateAudioManagerForSystemAudio(boolean on) { 8576b096d349b8ea879ee152a50df66427c919adabaJungshik Jang int device = mService.getAudioManager().setHdmiSystemAudioSupported(on); 8586b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]UpdateSystemAudio mode[on=%b] output=[%X]", on, device); 859377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 860377dcbd53af4529c352d453424539b069909fce4Jungshik Jang 861377dcbd53af4529c352d453424539b069909fce4Jungshik Jang boolean isSystemAudioActivated() { 86286a1e5a16ed6d49ecbdfe78c3ca7a9afc7814264Jinsuk Kim if (!hasSystemAudioDevice()) { 863377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return false; 864377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 86579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 866377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return mSystemAudioActivated; 86779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 86879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 86979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 870377dcbd53af4529c352d453424539b069909fce4Jungshik Jang boolean getSystemAudioModeSetting() { 871377dcbd53af4529c352d453424539b069909fce4Jungshik Jang return mService.readBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, false); 872377dcbd53af4529c352d453424539b069909fce4Jungshik Jang } 873377dcbd53af4529c352d453424539b069909fce4Jungshik Jang 87479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 87579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Change ARC status into the given {@code enabled} status. 87679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 87779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @return {@code true} if ARC was in "Enabled" status 87879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 879a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 88079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang boolean setArcStatus(boolean enabled) { 881a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 8826b096d349b8ea879ee152a50df66427c919adabaJungshik Jang 8836b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled); 884a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang boolean oldStatus = mArcEstablished; 885a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 1. Enable/disable ARC circuit. 886757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim setAudioReturnChannel(enabled); 887a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 2. Notify arc status to audio service. 888a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang notifyArcStatusToAudioService(enabled); 889a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // 3. Update arc status; 890a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang mArcEstablished = enabled; 891a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return oldStatus; 89279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 89379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 894757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim /** 895757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim * Switch hardware ARC circuit in the system. 896757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim */ 897757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim @ServiceThreadOnly 898757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim void setAudioReturnChannel(boolean enabled) { 899757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim assertRunOnServiceThread(); 900757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim HdmiDeviceInfo avr = getAvrDeviceInfo(); 901757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim if (avr != null) { 902757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim mService.setAudioReturnChannel(avr.getPortId(), enabled); 903757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim } 904757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim } 905757c097753a166a6f3ecbbcbf42075ce3ba1a7edJinsuk Kim 9062ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim @ServiceThreadOnly 9072ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim private void updateArcFeatureStatus(int portId, boolean isConnected) { 9082ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim assertRunOnServiceThread(); 90937f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim HdmiPortInfo portInfo = mService.getPortInfo(portId); 91037f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (!portInfo.isArcSupported()) { 91137f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim return; 91237f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim } 913a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim HdmiDeviceInfo avr = getAvrDeviceInfo(); 914a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim if (avr == null) { 91537f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (isConnected) { 91637f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim // Update the status (since TV may not have seen AVR yet) so 91737f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim // that ARC can be initiated after discovery. 91837f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim mArcFeatureEnabled.put(portId, isConnected); 91937f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim } 920a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim return; 921a6d5dad9bf1f43e2b4cdf18728a4b7a0d4d76bb5Jinsuk Kim } 9222ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim // HEAC 2.4, HEACT 5-15 9232ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim // Should not activate ARC if +5V status is false. 92437f5bc281c40965f8604400d700e68c0d17e77b0Jinsuk Kim if (avr.getPortId() == portId) { 9255bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim changeArcFeatureEnabled(portId, isConnected); 9262ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim } 9272ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim } 9282ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim 9297b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim @ServiceThreadOnly 9307b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim boolean isConnected(int portId) { 9317b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim assertRunOnServiceThread(); 9327b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim return mService.isConnected(portId); 9337b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim } 9347b0cf6413218e5b5c549eea31733222fcffafabcJinsuk Kim 935a858d221ff86c497e745222ea15bab141e337636Jungshik Jang private void notifyArcStatusToAudioService(boolean enabled) { 936a858d221ff86c497e745222ea15bab141e337636Jungshik Jang // Note that we don't set any name to ARC. 937a858d221ff86c497e745222ea15bab141e337636Jungshik Jang mService.getAudioManager().setWiredDeviceConnectionState( 938a858d221ff86c497e745222ea15bab141e337636Jungshik Jang AudioSystem.DEVICE_OUT_HDMI_ARC, 93910804eb2818ab59b763a37b4f6151693c2ebba7bPaul McLean enabled ? 1 : 0, "", ""); 940a858d221ff86c497e745222ea15bab141e337636Jungshik Jang } 941a858d221ff86c497e745222ea15bab141e337636Jungshik Jang 94279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 9435bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim * Returns true if ARC is currently established on a certain port. 94479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 945a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 9465bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim boolean isArcEstablished() { 947a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 9485bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcEstablished) { 9495bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim for (int i = 0; i < mArcFeatureEnabled.size(); i++) { 9505bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcFeatureEnabled.valueAt(i)) return true; 9515bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 9525bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim } 9535bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return false; 954a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 955a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 956a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 9575bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim void changeArcFeatureEnabled(int portId, boolean enabled) { 958a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 959a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 9605bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (mArcFeatureEnabled.get(portId) != enabled) { 9615bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim mArcFeatureEnabled.put(portId, enabled); 962a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (enabled) { 963a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!mArcEstablished) { 964a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang startArcAction(true); 965a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 966a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } else { 967a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (mArcEstablished) { 968a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang startArcAction(false); 969a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 970a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 971a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 972a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 973a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 974a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 9755bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim boolean isArcFeatureEnabled(int portId) { 976a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 9775bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return mArcFeatureEnabled.get(portId); 978a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 979a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 980a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang @ServiceThreadOnly 981339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang void startArcAction(boolean enabled) { 982a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang assertRunOnServiceThread(); 98361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = getAvrDeviceInfo(); 984a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (info == null) { 985339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Slog.w(TAG, "Failed to start arc action; No AVR device."); 986a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 987a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 988339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!canStartArcUpdateAction(info.getLogicalAddress(), enabled)) { 989339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang Slog.w(TAG, "Failed to start arc action; ARC configuration check failed."); 990339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (enabled && !isConnectedToArcPort(info.getPhysicalAddress())) { 991339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT); 992339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 993a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang return; 994a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 995a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang 996a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang // Terminate opposite action and start action if not exist. 997a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (enabled) { 998a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang removeAction(RequestArcTerminationAction.class); 999a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!hasAction(RequestArcInitiationAction.class)) { 1000a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang addAndStartAction(new RequestArcInitiationAction(this, info.getLogicalAddress())); 1001a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 1002a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } else { 1003a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang removeAction(RequestArcInitiationAction.class); 1004a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang if (!hasAction(RequestArcTerminationAction.class)) { 1005a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang addAndStartAction(new RequestArcTerminationAction(this, info.getLogicalAddress())); 1006a13da0d5913757e2456020c69481f98d0e44c090Jungshik Jang } 100779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 100879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 100979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1010339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang private boolean isDirectConnectAddress(int physicalAddress) { 1011339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return (physicalAddress & Constants.ROUTING_PATH_TOP_MASK) == physicalAddress; 1012339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1013339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 101479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void setAudioStatus(boolean mute, int volume) { 10158fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang synchronized (mLock) { 10168fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mSystemAudioMute = mute; 10178fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mSystemAudioVolume = volume; 1018b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang int maxVolume = mService.getAudioManager().getStreamMaxVolume( 1019b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang AudioManager.STREAM_MUSIC); 1020b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang mService.setAudioStatus(mute, 1021b69aafbfaddd8a6ac84b366b5db640cdd7e95354Jungshik Jang VolumeControlAction.scaleToCustomVolume(volume, maxVolume)); 10222e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang displayOsd(HdmiControlManager.OSD_MESSAGE_AVR_VOLUME_CHANGED, 10232e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mute ? HdmiControlManager.AVR_VOLUME_MUTED : volume); 10248fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10258fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10268fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10278fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @ServiceThreadOnly 10288fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang void changeVolume(int curVolume, int delta, int maxVolume) { 10298fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 1030377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (delta == 0 || !isSystemAudioActivated()) { 10318fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10328fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10338fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10348fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int targetVolume = curVolume + delta; 10358fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang int cecVolume = VolumeControlAction.scaleToCecVolume(targetVolume, maxVolume); 10368fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang synchronized (mLock) { 10378fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // If new volume is the same as current system audio volume, just ignore it. 10388fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Note that UNKNOWN_VOLUME is not in range of cec volume scale. 10398fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang if (cecVolume == mSystemAudioVolume) { 10408fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Update tv volume with system volume value. 10418fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang mService.setAudioStatus(false, 10428fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang VolumeControlAction.scaleToCustomVolume(mSystemAudioVolume, maxVolume)); 10438fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10448fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10458fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10468fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10472e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang List<VolumeControlAction> actions = getActions(VolumeControlAction.class); 10482e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang if (actions.isEmpty()) { 10492e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang addAndStartAction(new VolumeControlAction(this, 10502e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang getAvrDeviceInfo().getLogicalAddress(), delta > 0)); 10512e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } else { 10522e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang actions.get(0).handleVolumeChange(delta > 0); 10532e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 10548fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10558fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10568fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang @ServiceThreadOnly 10578fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang void changeMute(boolean mute) { 10588fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang assertRunOnServiceThread(); 10596b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]:Change mute:%b", mute); 1060720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang synchronized (mLock) { 1061720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang if (mSystemAudioMute == mute) { 1062720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang HdmiLogger.debug("No need to change mute."); 1063720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang return; 1064720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang } 1065720407ad06dbf4486ef6d724280640990d2fcd2aJungshik Jang } 1066377dcbd53af4529c352d453424539b069909fce4Jungshik Jang if (!isSystemAudioActivated()) { 10676b096d349b8ea879ee152a50df66427c919adabaJungshik Jang HdmiLogger.debug("[A]:System audio is not activated."); 10688fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return; 10698fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10708fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 10718fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang // Remove existing volume action. 10728fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang removeAction(VolumeControlAction.class); 10732e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang sendUserControlPressedAndReleased(getAvrDeviceInfo().getLogicalAddress(), 10742e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mute ? HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION : 10752e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION); 10768fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 10778fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 107879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1079a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 108079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleInitiateArc(HdmiCecMessage message) { 108179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 1082339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 1083339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!canStartArcUpdateAction(message.getSource(), true)) { 10847fa3a66470d2133796defd14a0600578758882acJinsuk Kim if (getAvrDeviceInfo() == null) { 10857fa3a66470d2133796defd14a0600578758882acJinsuk Kim // AVR may not have been discovered yet. Delay the message processing. 10867fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.add(message); 10877fa3a66470d2133796defd14a0600578758882acJinsuk Kim return true; 10887fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 1089339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); 1090339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (!isConnectedToArcPort(message.getSource())) { 1091339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang displayOsd(OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT); 1092339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1093339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return true; 1094339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1095339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 109679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // In case where <Initiate Arc> is started by <Request ARC Initiation> 109779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // need to clean up RequestArcInitiationAction. 109879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(RequestArcInitiationAction.class); 109979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 110079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang message.getSource(), true); 110179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 110279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 110379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 110479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1105339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang private boolean canStartArcUpdateAction(int avrAddress, boolean shouldCheckArcFeatureEnabled) { 1106339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 1107339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (avr != null 1108339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && (avrAddress == avr.getLogicalAddress()) 1109339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && isConnectedToArcPort(avr.getPhysicalAddress()) 1110339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang && isDirectConnectAddress(avr.getPhysicalAddress())) { 1111339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang if (shouldCheckArcFeatureEnabled) { 11125bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim return isArcFeatureEnabled(avr.getPortId()); 1113339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } else { 1114339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return true; 1115339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1116339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } else { 1117339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang return false; 1118339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1119339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang } 1120339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang 112179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1122a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 112379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleTerminateArc(HdmiCecMessage message) { 112479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 11257e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim if (mService .isPowerStandbyOrTransient()) { 11267e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim setArcStatus(false); 11277e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim return true; 11287e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim } 11297e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // Do not check ARC configuration since the AVR might have been already removed. 11307e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // Clean up RequestArcTerminationAction in case <Terminate Arc> was started by 11317e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim // <Request ARC Termination>. 113279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeAction(RequestArcTerminationAction.class); 113379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SetArcTransmissionStateAction action = new SetArcTransmissionStateAction(this, 113479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang message.getSource(), false); 113579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 113679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 113779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 113879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 113979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1140a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 114179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { 114279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 114379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isMessageForSystemAudio(message)) { 1144ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim if (getAvrDeviceInfo() == null) { 1145ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim // AVR may not have been discovered yet. Delay the message processing. 1146ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim mDelayedMessageBuffer.add(message); 1147ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim return true; 1148ad1e3d7df42376cd2a257b6c3b2fed540658a6e3Jinsuk Kim } 11492e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Invalid <Set System Audio Mode> message:" + message); 11504480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang mService.maySendFeatureAbortCommand(message, Constants.ABORT_REFUSED); 11514480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 115279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 115379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this, 11547f0a1c54a837da7ebbb6f7eb56f44894e0df22c2Jungshik Jang message.getSource(), HdmiUtils.parseCommandParamSystemAudioStatus(message), null); 115579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang addAndStartAction(action); 115679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 115779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 115879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 115979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1160a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 116179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { 116279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 116379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isMessageForSystemAudio(message)) { 11642e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang HdmiLogger.warning("Invalid <System Audio Mode Status> message:" + message); 11654480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang // Ignore this message. 11664480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return true; 116779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 11687ecfbaed6e902aea151bc1919cf7771bbd868fc4Jinsuk Kim setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message), true); 116979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 117079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 117179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1172b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Seq #53 1173b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @Override 1174b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1175b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang protected boolean handleRecordTvScreen(HdmiCecMessage message) { 1176b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang List<OneTouchRecordAction> actions = getActions(OneTouchRecordAction.class); 1177b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!actions.isEmpty()) { 1178b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Assumes only one OneTouchRecordAction. 1179b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang OneTouchRecordAction action = actions.get(0); 1180b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (action.getRecorderAddress() != message.getSource()) { 118112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang announceOneTouchRecordResult( 1182326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang message.getSource(), 118312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang HdmiControlManager.ONE_TOUCH_RECORD_PREVIOUS_RECORDING_IN_PROGRESS); 1184b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1185b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return super.handleRecordTvScreen(message); 1186b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1187b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1188b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang int recorderAddress = message.getSource(); 1189b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang byte[] recordSource = mService.invokeRecordRequestListener(recorderAddress); 11904480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int reason = startOneTouchRecord(recorderAddress, recordSource); 11914480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang if (reason != Constants.ABORT_NO_ERROR) { 11924480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang mService.maySendFeatureAbortCommand(message, reason); 11934480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 1194b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 1195b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1196b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1197e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang @Override 1198e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang protected boolean handleTimerClearedStatus(HdmiCecMessage message) { 1199e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang byte[] params = message.getParams(); 1200e9e0f070e34a612fb3bab5d97bdec1e266da4a20Jungshik Jang int timerClearedStatusData = params[0] & 0xFF; 1201326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(message.getSource(), timerClearedStatusData); 1202e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return true; 1203e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1204e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1205326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceOneTouchRecordResult(int recorderAddress, int result) { 1206326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeOneTouchRecordResult(recorderAddress, result); 120712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 120812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1209326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceTimerRecordingResult(int recorderAddress, int result) { 1210326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeTimerRecordingResult(recorderAddress, result); 121112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 121212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 1213326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang void announceClearTimerRecordingResult(int recorderAddress, int result) { 1214326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang mService.invokeClearTimerRecordingResult(recorderAddress, result); 1215faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang } 1216faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang 121779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean isMessageForSystemAudio(HdmiCecMessage message) { 12184480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return mService.isControlEnabled() 12194480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang && message.getSource() == Constants.ADDR_AUDIO_SYSTEM 1220473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang && (message.getDestination() == Constants.ADDR_TV 1221473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang || message.getDestination() == Constants.ADDR_BROADCAST) 1222473119fdc36340f833e4b755ae7f50a6914e0a24Jungshik Jang && getAvrDeviceInfo() != null; 122379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 122479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 122579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 122661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Add a new {@link HdmiDeviceInfo}. It returns old device info which has the same 122779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * logical address as new device info's. 122879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 122979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 123079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 123161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @param deviceInfo a new {@link HdmiDeviceInfo} to be added. 123261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@code null} if it is new device. Otherwise, returns old {@HdmiDeviceInfo} 123379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * that has the same logical address as new one has. 123479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1235a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 123661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private HdmiDeviceInfo addDeviceInfo(HdmiDeviceInfo deviceInfo) { 123779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 12388960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo oldDeviceInfo = getCecDeviceInfo(deviceInfo.getLogicalAddress()); 123979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (oldDeviceInfo != null) { 12408960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim removeDeviceInfo(deviceInfo.getId()); 124179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 12428960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mDeviceInfos.append(deviceInfo.getId(), deviceInfo); 1243fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 124479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return oldDeviceInfo; 124579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 124679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 124779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 124879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Remove a device info corresponding to the given {@code logicalAddress}. 124961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * It returns removed {@link HdmiDeviceInfo} if exists. 125079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 125179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 125279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 12538960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * @param id id of device to be removed 125461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return removed {@link HdmiDeviceInfo} it exists. Otherwise, returns {@code null} 125579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1256a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 12578960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim private HdmiDeviceInfo removeDeviceInfo(int id) { 125879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 12598960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo deviceInfo = mDeviceInfos.get(id); 126079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (deviceInfo != null) { 12618960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim mDeviceInfos.remove(id); 126279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 1263fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang updateSafeDeviceInfoList(); 126479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return deviceInfo; 126579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 126679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 126779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 126861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Return a list of all {@link HdmiDeviceInfo}. 126979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 127079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * <p>Declared as package-private. accessed by {@link HdmiControlService} only. 1271339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang * This is not thread-safe. For thread safety, call {@link #getSafeExternalInputsLocked} which 12728e93c84739902f5adaa499b474f39e3c4807bc1cJungshik Jang * does not include local device. 127379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1274a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 12754b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim List<HdmiDeviceInfo> getDeviceInfoList(boolean includeLocalDevice) { 127679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 12774b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim if (includeLocalDevice) { 1278fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang return HdmiUtils.sparseArrayToList(mDeviceInfos); 127979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } else { 128061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 128179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang for (int i = 0; i < mDeviceInfos.size(); ++i) { 128261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = mDeviceInfos.valueAt(i); 128379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!isLocalDeviceAddress(info.getLogicalAddress())) { 128479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang infoList.add(info); 128579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 128679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 128779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return infoList; 128879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 128979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 129079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1291fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang /** 12929c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * Return external input devices. 1293fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang */ 1294ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim List<HdmiDeviceInfo> getSafeExternalInputsLocked() { 1295ed0864557b3340ab7db00e2dc95b29c4b8bb485dJinsuk Kim return mSafeExternalInputs; 1296fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1297fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 1298a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1299fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang private void updateSafeDeviceInfoList() { 1300fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang assertRunOnServiceThread(); 130161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang List<HdmiDeviceInfo> copiedDevices = HdmiUtils.sparseArrayToList(mDeviceInfos); 130261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang List<HdmiDeviceInfo> externalInputs = getInputDevices(); 1303fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang synchronized (mLock) { 1304fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang mSafeAllDeviceInfos = copiedDevices; 13059c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim mSafeExternalInputs = externalInputs; 13069c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13079c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13089c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim 13099c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim /** 13109c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * Return a list of external cec input (source) devices. 13119c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * 13129c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * <p>Note that this effectively excludes non-source devices like system audio, 13139c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim * secondary TV. 13149c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim */ 131561f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private List<HdmiDeviceInfo> getInputDevices() { 131661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 13179c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim for (int i = 0; i < mDeviceInfos.size(); ++i) { 131861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo info = mDeviceInfos.valueAt(i); 13198960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (isLocalDeviceAddress(info.getLogicalAddress())) { 13209c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim continue; 13219c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 13224fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (info.isSourceType() && !hideDevicesBehindLegacySwitch(info)) { 13239c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim infoList.add(info); 13249c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim } 1325fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 13269c37e1f53ea4734bfe5ae156dc5399ce5f2c7cccJinsuk Kim return infoList; 1327fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1328fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 13294fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // Check if we are hiding CEC devices connected to a legacy (non-CEC) switch. 13304fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // Returns true if the policy is set to true, and the device to check does not have 13314fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // a parent CEC device (which should be the CEC-enabled switch) in the list. 133261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang private boolean hideDevicesBehindLegacySwitch(HdmiDeviceInfo info) { 13334fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return HdmiConfig.HIDE_DEVICES_BEHIND_LEGACY_SWITCH 13344fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim && !isConnectedToCecSwitch(info.getPhysicalAddress(), mCecSwitches); 13354fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13364fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 13374fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private static boolean isConnectedToCecSwitch(int path, Collection<Integer> switches) { 13384fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim for (int switchPath : switches) { 13394fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (isParentPath(switchPath, path)) { 13404fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return true; 13414fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13424fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13434fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return false; 13444fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13454fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 13464fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private static boolean isParentPath(int parentPath, int childPath) { 13474fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // (A000, AB00) (AB00, ABC0), (ABC0, ABCD) 13484fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim // If child's last non-zero nibble is removed, the result equals to the parent. 13494fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim for (int i = 0; i <= 12; i += 4) { 13504fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int nibble = (childPath >> i) & 0xF; 13514fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (nibble != 0) { 13524fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int parentNibble = (parentPath >> i) & 0xF; 13534fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return parentNibble == 0 && (childPath >> i+4) == (parentPath >> i+4); 13544fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13554fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13564fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim return false; 13574fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13584fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 135961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang private void invokeDeviceEventListener(HdmiDeviceInfo info, int status) { 136098d760e1c3123e6db8459f605d59a5689d56268cJinsuk Kim if (!hideDevicesBehindLegacySwitch(info)) { 136161daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang mService.invokeDeviceEventListeners(info, status); 13624fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13634fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 13644fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 136579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean isLocalDeviceAddress(int address) { 1366bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return mLocalDeviceAddresses.contains(address); 136779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 136879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1369e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang @ServiceThreadOnly 137061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getAvrDeviceInfo() { 1371e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang assertRunOnServiceThread(); 13728960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return getCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); 1373e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang } 1374e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang 137579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 137661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Return a {@link HdmiDeviceInfo} corresponding to the given {@code logicalAddress}. 137779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 13788960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * This is not thread-safe. For thread safety, call {@link #getSafeCecDeviceInfo(int)}. 137979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 1380339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang * @param logicalAddress logical address of the device to be retrieved 138161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. 138279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Returns null if no logical address matched 138379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1384a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 13858960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo getCecDeviceInfo(int logicalAddress) { 138679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 13878960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return mDeviceInfos.get(HdmiDeviceInfo.idForCecDevice(logicalAddress)); 138879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 138979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 1390e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang boolean hasSystemAudioDevice() { 1391e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang return getSafeAvrDeviceInfo() != null; 1392e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang } 1393e9cf1583c74fd03977c1ecb14520663710f14439Jungshik Jang 139461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getSafeAvrDeviceInfo() { 13958960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return getSafeCecDeviceInfo(Constants.ADDR_AUDIO_SYSTEM); 139679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 139779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 139879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 13998960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim * Thread safe version of {@link #getCecDeviceInfo(int)}. 1400fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * 1401fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * @param logicalAddress logical address to be retrieved 140261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} matched with the given {@code logicalAddress}. 1403fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang * Returns null if no logical address matched 1404fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang */ 14058960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo getSafeCecDeviceInfo(int logicalAddress) { 1406fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang synchronized (mLock) { 14078960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 14088960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim if (info.isCecDevice() && info.getLogicalAddress() == logicalAddress) { 14098960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return info; 14108960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 14118960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim } 14128960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim return null; 1413fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1414fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang } 1415fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang 1416bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim List<HdmiDeviceInfo> getSafeCecDevicesLocked() { 1417bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); 1418bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 1419bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim if (isLocalDeviceAddress(info.getLogicalAddress())) { 1420bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim continue; 1421bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1422bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim infoList.add(info); 1423bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1424bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim return infoList; 1425bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim } 1426bdf27fbf746bee11430c4db2ea6dfd026bae77feJinsuk Kim 1427fa8e90db6a84ce1b19af86d46b547664d8a7ac37Jungshik Jang /** 14288f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang * Called when a device is newly added or a new device is detected or 14298f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang * existing device is updated. 143079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 143179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param info device info of a new device. 143279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1433a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 143461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang final void addCecDevice(HdmiDeviceInfo info) { 143579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 14366102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim HdmiDeviceInfo old = addDeviceInfo(info); 143713c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim if (info.getLogicalAddress() == mAddress) { 143813c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim // The addition of TV device itself should not be notified. 143913c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim return; 144013c030e828a90fcfc57b52024b72326757cec583Jinsuk Kim } 14416102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim if (old == null) { 14426102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); 14436102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim } else if (!old.equals(info)) { 14444fcbf0b93e15e60eeb8b08a32d895de07c73cb1bJinsuk Kim invokeDeviceEventListener(old, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 14454fcbf0b93e15e60eeb8b08a32d895de07c73cb1bJinsuk Kim invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_ADD_DEVICE); 14466102bac706d351ce52ce385745f30aecaf835a2aJinsuk Kim } 144779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 144879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 144979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 145079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Called when a device is removed or removal of device is detected. 145179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 145279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param address a logical address of a device to be removed 145379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1454a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 145579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final void removeCecDevice(int address) { 145679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 14578960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = removeDeviceInfo(HdmiDeviceInfo.idForCecDevice(address)); 145826dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang 145979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecMessageCache.flushMessagesFrom(address); 146061daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(info, HdmiControlManager.DEVICE_EVENT_REMOVE_DEVICE); 146179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 146279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 146326dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang @ServiceThreadOnly 146426dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang void handleRemoveActiveRoutingPath(int path) { 146526dc71e7feefb2417fd5f007af68614c1c197cf8Jungshik Jang assertRunOnServiceThread(); 146692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #23 146792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim if (isTailOfActivePath(path, getActivePath())) { 146892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 1469546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, true, null); 147092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 147192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 147292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 14735344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim /** 14745344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * Launch routing control process. 14755344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * 14765344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * @param routingForBootup true if routing control is initiated due to One Touch Play 14775344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim * or TV power on 14785344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim */ 147992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim @ServiceThreadOnly 14805344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim void launchRoutingControl(boolean routingForBootup) { 148192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim assertRunOnServiceThread(); 148292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim // Seq #24 1483c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (getActivePortId() != Constants.INVALID_PORT_ID) { 14845344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim if (!routingForBootup && !isProhibitMode()) { 14855344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim int newPath = mService.portIdToPath(getActivePortId()); 14865344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim setActivePath(newPath); 1487546d867cb89099ed9036d54d1d49e11748c9a27eJinsuk Kim startRoutingControl(getActivePath(), newPath, routingForBootup, null); 14885344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim } 148992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } else { 149092b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim int activePath = mService.getPhysicalAddress(); 149192b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim setActivePath(activePath); 14922ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim if (!routingForBootup 14932ab6d9fff36836c71bc0ee4afa25c11b48a9bd99Jinsuk Kim && !mDelayedMessageBuffer.isBuffered(Constants.MESSAGE_ACTIVE_SOURCE)) { 14945344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource(mAddress, 14955344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim activePath)); 14965344cd98e69f92e70d52969b1851c9d8f9e81853Jinsuk Kim } 149792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 149892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 149992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 150079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 150161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * Returns the {@link HdmiDeviceInfo} instance whose physical address matches 150279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * the given routing path. CEC devices use routing path for its physical address to 150379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * describe the hierarchy of the devices in the network. 150479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 150579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param path routing path or physical address 150661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null 150779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1508a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 150961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang final HdmiDeviceInfo getDeviceInfoByPath(int path) { 151079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 151161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang for (HdmiDeviceInfo info : getDeviceInfoList(false)) { 151279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (info.getPhysicalAddress() == path) { 151379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return info; 151479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 151579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 151679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return null; 151779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 151879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 151979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 15207640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * Returns the {@link HdmiDeviceInfo} instance whose physical address matches 15217640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * the given routing path. This is the version accessible safely from threads 15227640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * other than service thread. 15237640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * 15247640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * @param path routing path or physical address 15257640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim * @return {@link HdmiDeviceInfo} if the matched info is found; otherwise null 15267640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim */ 15277640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim HdmiDeviceInfo getSafeDeviceInfoByPath(int path) { 15287640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim synchronized (mLock) { 15297640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 15307640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim if (info.getPhysicalAddress() == path) { 15317640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim return info; 15327640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15337640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15347640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim return null; 15357640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15367640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim } 15377640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim 15387640d9895cf8fae7a99a7db5bba0079ba6022621Jinsuk Kim /** 153979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Whether a device of the specified physical address and logical address exists 154079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * in a device info list. However, both are minimal condition and it could 154179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * be different device from the original one. 154279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 154379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param logicalAddress logical address of a device to be searched 154492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim * @param physicalAddress physical address of a device to be searched 154579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @return true if exist; otherwise false 154679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 1547a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 15487cd4a589af7cc6e6880799e86ef6febca5add46dJinsuk Kim boolean isInDeviceList(int logicalAddress, int physicalAddress) { 154979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 15508960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo device = getCecDeviceInfo(logicalAddress); 155179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (device == null) { 155279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 155379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 155479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return device.getPhysicalAddress() == physicalAddress; 155579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 155679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 155779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @Override 1558a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 155992b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim void onHotplug(int portId, boolean connected) { 156079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 156179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 15624fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (!connected) { 15634fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim removeCecSwitches(portId); 15644fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 156579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Tv device will have permanent HotplugDetectionAction. 156679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang List<HotplugDetectionAction> hotplugActions = getActions(HotplugDetectionAction.class); 156779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (!hotplugActions.isEmpty()) { 156879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Note that hotplug action is single action running on a machine. 156979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // "pollAllDevicesNow" cleans up timer and start poll action immediately. 157024c23c1dd82870be4c09f3c5b6ae354de722de94Jungshik Jang // It covers seq #40, #43. 157179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang hotplugActions.get(0).pollAllDevicesNow(); 157279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 15732ee0d6f44d7274bb1846cc6ff7a60451539a2b51Jinsuk Kim updateArcFeatureStatus(portId, connected); 157460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 1575160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim 15764fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim private void removeCecSwitches(int portId) { 15774fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim Iterator<Integer> it = mCecSwitches.iterator(); 15784fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim while (!it.hasNext()) { 15794fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim int path = it.next(); 15804fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim if (pathToPortId(path) == portId) { 15814fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim it.remove(); 15824fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 15834fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 15844fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim } 15854fdd0f47bc10bdbc429c6316c2cc98a747570b12Jinsuk Kim 1586e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim @Override 1587160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim @ServiceThreadOnly 1588160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim void setAutoDeviceOff(boolean enabled) { 1589160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim assertRunOnServiceThread(); 1590160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim mAutoDeviceOff = enabled; 1591544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim } 1592544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim 1593544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim @ServiceThreadOnly 1594544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim void setAutoWakeup(boolean enabled) { 1595544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim assertRunOnServiceThread(); 1596544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim mAutoWakeup = enabled; 1597160a6e5b99de15ce755e2e5521dce32d81ab180aJinsuk Kim } 159838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 159925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo @ServiceThreadOnly 160025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean getAutoWakeup() { 160125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo assertRunOnServiceThread(); 160225c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo return mAutoWakeup; 160325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo } 160425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo 160538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 160638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 16074fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) { 160838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 16097fa3a66470d2133796defd14a0600578758882acJinsuk Kim mService.unregisterTvInputCallback(mTvInputCallback); 161038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Remove any repeated working actions. 161138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // HotplugDetectionAction will be reinstated during the wake up process. 161238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // HdmiControlService.onWakeUp() -> initializeLocalDevices() -> 161338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // LocalDeviceTv.onAddressAllocated() -> launchDeviceDiscovery(). 16144fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(DeviceDiscoveryAction.class); 161538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo removeAction(HotplugDetectionAction.class); 1616410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang removeAction(PowerStatusMonitorAction.class); 1617faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang // Remove recording actions. 1618b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang removeAction(OneTouchRecordAction.class); 1619faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang removeAction(TimerRecordingAction.class); 16204fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableSystemAudioIfExist(); 16224fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang disableArcIfExist(); 1623a5445ce992a4e8ac5252975acedf3e5aec53867aJinsuk Kim 1624a5445ce992a4e8ac5252975acedf3e5aec53867aJinsuk Kim super.disableDevice(initiatedByCec, callback); 162549b47bbef8a8d27e9707d5d24848040519586a7aJinsuk Kim clearDeviceInfoList(); 16267cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim getActiveSource().invalidate(); 16277cc51c631d6e7e5680ce661089524b7335d88756Jinsuk Kim setActivePath(Constants.INVALID_PHYSICAL_ADDRESS); 162838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 162938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 163038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 16314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 16324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableSystemAudioIfExist() { 16334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 16344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (getAvrDeviceInfo() == null) { 16354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 16364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Seq #31. 16394fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioActionFromAvr.class); 16404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioActionFromTv.class); 16414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioAutoInitiationAction.class); 16424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(SystemAudioStatusAction.class); 16434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(VolumeControlAction.class); 16444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 16474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void disableArcIfExist() { 16484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 164961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo avr = getAvrDeviceInfo(); 16504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (avr == null) { 16514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang return; 16524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 16544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Seq #44. 16554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang removeAction(RequestArcInitiationAction.class); 16565bcf5bf6b4203629e153dcb0646596e9b3f7c7c2Jinsuk Kim if (!hasAction(RequestArcTerminationAction.class) && isArcEstablished()) { 16574fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang addAndStartAction(new RequestArcTerminationAction(this, avr.getLogicalAddress())); 16584fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16594fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 16604fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 166138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @Override 166238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 1663e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim protected void onStandby(boolean initiatedByCec, int standbyAction) { 166438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 166538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Seq #11 166638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (!mService.isControlEnabled()) { 166738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 166838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 1669544b62bb863788727587ee292596451e461fc0a7Jinsuk Kim if (!initiatedByCec && mAutoDeviceOff) { 167038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby( 1671c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress, Constants.ADDR_BROADCAST)); 167238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 167438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 16754d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim boolean isProhibitMode() { 16764d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim return mService.isProhibitMode(); 16774d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim } 1678b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim 1679b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim boolean isPowerStandbyOrTransient() { 1680b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim return mService.isPowerStandbyOrTransient(); 16818866c810b6778714da69ebc023ed432491caad92Jungshik Jang } 1682c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim 1683339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang @ServiceThreadOnly 1684c7eba0f1db8928ca779933a564a06989e22a8532Jinsuk Kim void displayOsd(int messageId) { 1685339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang assertRunOnServiceThread(); 1686339227da7cf025ce4ae0c85ddc52643d63972321Jungshik Jang mService.displayOsd(messageId); 1687b38cd68b240d99e8c8ae6ff1802a574696b420cdJinsuk Kim } 1688b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 16892e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang @ServiceThreadOnly 16902e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void displayOsd(int messageId, int extra) { 16912e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang assertRunOnServiceThread(); 16922e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mService.displayOsd(messageId, extra); 16932e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 16942e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 1695b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Seq #54 and #55 1696b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 16974480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang int startOneTouchRecord(int recorderAddress, byte[] recordSource) { 1698b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1699b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!mService.isControlEnabled()) { 1700b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1701326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED); 17024480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NOT_IN_CORRECT_MODE; 1703b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1704b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1705b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecorder(recorderAddress)) { 1706b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1707326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1708326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 17094480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NOT_IN_CORRECT_MODE; 1710b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1711b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1712b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecordSource(recordSource)) { 1713b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 1714326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1715326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_FAIL_TO_RECORD_DISPLAYED_SCREEN); 1716d47abefc8269dae7fdfa2bb102bcb89cbea7c7b0Jinsuk Kim return Constants.ABORT_CANNOT_PROVIDE_SOURCE; 1717b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1718b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1719b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang addAndStartAction(new OneTouchRecordAction(this, recorderAddress, recordSource)); 1720b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.i(TAG, "Start new [One Touch Record]-Target:" + recorderAddress + ", recordSource:" 1721b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang + Arrays.toString(recordSource)); 17224480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return Constants.ABORT_NO_ERROR; 1723b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1724b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1725b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1726b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void stopOneTouchRecord(int recorderAddress) { 1727b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1728b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!mService.isControlEnabled()) { 1729b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Can not stop one touch record. CEC control is disabled."); 1730326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, ONE_TOUCH_RECORD_CEC_DISABLED); 1731b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1732b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1733b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1734b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang if (!checkRecorder(recorderAddress)) { 1735b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1736326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceOneTouchRecordResult(recorderAddress, 1737326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang ONE_TOUCH_RECORD_CHECK_RECORDER_CONNECTION); 1738b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return; 1739b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1740b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1741b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang // Remove one touch record action so that other one touch record can be started. 1742b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang removeAction(OneTouchRecordAction.class); 1743b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildRecordOff(mAddress, recorderAddress)); 1744b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang Slog.i(TAG, "Stop [One Touch Record]-Target:" + recorderAddress); 1745b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1746b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1747b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private boolean checkRecorder(int recorderAddress) { 17488960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo device = getCecDeviceInfo(recorderAddress); 1749b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return (device != null) 1750b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang && (HdmiUtils.getTypeFromAddress(recorderAddress) 175161f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang == HdmiDeviceInfo.DEVICE_RECORDER); 1752b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1753b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1754b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang private boolean checkRecordSource(byte[] recordSource) { 1755b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return (recordSource != null) && HdmiRecordSources.checkRecordSource(recordSource); 1756b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1757b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1758b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1759b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void startTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) { 1760b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 176112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!mService.isControlEnabled()) { 176212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1763326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(recorderAddress, 1764326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang TIMER_RECORDING_RESULT_EXTRA_CEC_DISABLED); 176512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 176612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 1767b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 176812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!checkRecorder(recorderAddress)) { 176912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1770326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceTimerRecordingResult(recorderAddress, 1771e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang TIMER_RECORDING_RESULT_EXTRA_CHECK_RECORDER_CONNECTION); 177212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 177312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 177412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 177512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang if (!checkTimerRecordingSource(sourceType, recordSource)) { 177612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 177712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang announceTimerRecordingResult( 1778326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang recorderAddress, 1779e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang TIMER_RECORDING_RESULT_EXTRA_FAIL_TO_RECORD_SELECTED_SOURCE); 178012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return; 178112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 178212e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 178312e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang addAndStartAction( 178412e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang new TimerRecordingAction(this, recorderAddress, sourceType, recordSource)); 178512e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang Slog.i(TAG, "Start [Timer Recording]-Target:" + recorderAddress + ", SourceType:" 178612e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang + sourceType + ", RecordSource:" + Arrays.toString(recordSource)); 178712e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang } 178812e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang 178912e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang private boolean checkTimerRecordingSource(int sourceType, byte[] recordSource) { 179012e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang return (recordSource != null) 179112e5dcefe136b58562f39604e6a8460ac92cb895Jungshik Jang && HdmiTimerRecordSources.checkTimerRecordSource(sourceType, recordSource); 1792b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1793b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1794b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang @ServiceThreadOnly 1795b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang void clearTimerRecording(int recorderAddress, int sourceType, byte[] recordSource) { 1796b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang assertRunOnServiceThread(); 1797e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!mService.isControlEnabled()) { 1798e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Can not start one touch record. CEC control is disabled."); 1799326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, CLEAR_TIMER_STATUS_CEC_DISABLE); 1800e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1801e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1802e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1803e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!checkRecorder(recorderAddress)) { 1804e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid recorder address:" + recorderAddress); 1805326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1806326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_CHECK_RECORDER_CONNECTION); 1807e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1808e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1809e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1810e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (!checkTimerRecordingSource(sourceType, recordSource)) { 1811e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid record source." + Arrays.toString(recordSource)); 1812326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1813326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1814e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1815e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1816e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1817e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang sendClearTimerMessage(recorderAddress, sourceType, recordSource); 1818e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1819e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 1820326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang private void sendClearTimerMessage(final int recorderAddress, int sourceType, 1821326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang byte[] recordSource) { 1822e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang HdmiCecMessage message = null; 1823e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang switch (sourceType) { 1824e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_DIGITAL: 1825e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearDigitalTimer(mAddress, recorderAddress, 1826e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1827e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1828e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_ANALOGUE: 1829e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearAnalogueTimer(mAddress, recorderAddress, 1830e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1831e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1832e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case TIMER_RECORDING_TYPE_EXTERNAL: 1833e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang message = HdmiCecMessageBuilder.buildClearExternalTimer(mAddress, recorderAddress, 1834e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang recordSource); 1835e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang break; 1836e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang default: 1837e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang Slog.w(TAG, "Invalid source type:" + recorderAddress); 1838326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1839326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1840e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return; 1841b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 1842e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1843e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang mService.sendCecCommand(message, new SendMessageCallback() { 1844e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang @Override 1845e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang public void onSendCompleted(int error) { 1846e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang if (error != Constants.SEND_RESULT_SUCCESS) { 1847326aef0c9402742e29c4503c857f93e75cf9a6ecJungshik Jang announceClearTimerRecordingResult(recorderAddress, 1848faa49bc896be859d5bcf2da3bddd4507b5e6494cJungshik Jang CLEAR_TIMER_STATUS_FAIL_TO_CLEAR_SELECTED_SOURCE); 1849e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1850e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 1851e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang }); 1852b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 1853410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1854410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang void updateDevicePowerStatus(int logicalAddress, int newPowerStatus) { 18558960d1b1552729e3dfd33deee951ac75933ad8e5Jinsuk Kim HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); 1856410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (info == null) { 1857410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang Slog.w(TAG, "Can not update power status of non-existing device:" + logicalAddress); 1858410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return; 1859410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1860410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1861410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang if (info.getDevicePowerStatus() == newPowerStatus) { 1862410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang return; 1863410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1864410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 1865410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang HdmiDeviceInfo newInfo = HdmiUtils.cloneHdmiDeviceInfo(info, newPowerStatus); 1866410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang // addDeviceInfo replaces old device info with new one if exists. 1867410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang addDeviceInfo(newInfo); 1868410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang 186961daf6b38e7a7ada2a6ca5a60539a54b9c6810bdJungshik Jang invokeDeviceEventListener(newInfo, HdmiControlManager.DEVICE_EVENT_UPDATE_DEVICE); 1870410ca9c7a4a2d69af5c81e76320433bfda05cafeJungshik Jang } 1871959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 1872959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 1873184b124ec22a796327642e3546d366179e693f07Yuncheol Heo protected boolean handleMenuStatus(HdmiCecMessage message) { 1874184b124ec22a796327642e3546d366179e693f07Yuncheol Heo // Do nothing and just return true not to prevent from responding <Feature Abort>. 1875184b124ec22a796327642e3546d366179e693f07Yuncheol Heo return true; 1876184b124ec22a796327642e3546d366179e693f07Yuncheol Heo } 1877184b124ec22a796327642e3546d366179e693f07Yuncheol Heo 1878184b124ec22a796327642e3546d366179e693f07Yuncheol Heo @Override 1879d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim protected void sendStandby(int deviceId) { 1880d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim HdmiDeviceInfo targetDevice = mDeviceInfos.get(deviceId); 1881d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim if (targetDevice == null) { 1882d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim return; 1883d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1884d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim int targetAddress = targetDevice.getLogicalAddress(); 1885d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim mService.sendCecCommand(HdmiCecMessageBuilder.buildStandby(mAddress, targetAddress)); 1886d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 1887d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 18887fa3a66470d2133796defd14a0600578758882acJinsuk Kim @ServiceThreadOnly 18897fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processAllDelayedMessages() { 18907fa3a66470d2133796defd14a0600578758882acJinsuk Kim assertRunOnServiceThread(); 18917fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.processAllMessages(); 18927fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 18937fa3a66470d2133796defd14a0600578758882acJinsuk Kim 18947fa3a66470d2133796defd14a0600578758882acJinsuk Kim @ServiceThreadOnly 18957fa3a66470d2133796defd14a0600578758882acJinsuk Kim void processDelayedMessages(int address) { 18967fa3a66470d2133796defd14a0600578758882acJinsuk Kim assertRunOnServiceThread(); 18977fa3a66470d2133796defd14a0600578758882acJinsuk Kim mDelayedMessageBuffer.processMessagesForDevice(address); 18987fa3a66470d2133796defd14a0600578758882acJinsuk Kim } 18997fa3a66470d2133796defd14a0600578758882acJinsuk Kim 19006e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim @ServiceThreadOnly 19016e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim void processDelayedActiveSource(int address) { 19026e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim assertRunOnServiceThread(); 19036e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim mDelayedMessageBuffer.processActiveSource(address); 19046e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 19056e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 1906d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim @Override 1907959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(final IndentingPrintWriter pw) { 1908959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo super.dump(pw); 1909959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mArcEstablished: " + mArcEstablished); 1910959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mArcFeatureEnabled: " + mArcFeatureEnabled); 1911959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSystemAudioActivated: " + mSystemAudioActivated); 1912959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSystemAudioMute: " + mSystemAudioMute); 1913959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAutoDeviceOff: " + mAutoDeviceOff); 1914959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAutoWakeup: " + mAutoWakeup); 1915959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mSkipRoutingControl: " + mSkipRoutingControl); 1916cb8661c08f4a7b00eaa2ede06a30c32dd3cbc53bJinsuk Kim pw.println("mPrevPortId: " + mPrevPortId); 19174b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.println("CEC devices:"); 19184b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.increaseIndent(); 19194b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { 19204b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.println(info); 19214b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim } 19224b4b940c69d22304eb0734ed2432fc70ebadd462Jinsuk Kim pw.decreaseIndent(); 1923959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 19242918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim} 1925