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 1961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jangimport android.hardware.hdmi.HdmiDeviceInfo; 203e1564ee397ef833cba351153029317786f3d6bbTerry Heoimport android.hardware.input.InputManager; 214fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport android.os.Handler; 2279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport android.os.Looper; 234fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jangimport android.os.Message; 243e1564ee397ef833cba351153029317786f3d6bbTerry Heoimport android.os.SystemClock; 25092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jangimport android.util.Slog; 263e1564ee397ef833cba351153029317786f3d6bbTerry Heoimport android.view.InputDevice; 273e1564ee397ef833cba351153029317786f3d6bbTerry Heoimport android.view.KeyCharacterMap; 283e1564ee397ef833cba351153029317786f3d6bbTerry Heoimport android.view.KeyEvent; 292918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 3079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport com.android.internal.annotations.GuardedBy; 31959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heoimport com.android.internal.util.IndentingPrintWriter; 32a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jangimport com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; 3379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 3479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.ArrayList; 3543c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kimimport java.util.Collections; 3679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.Iterator; 3779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.List; 3879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 392918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/** 402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Class that models a logical CEC device hosted in this system. Handles initialization, 412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * CEC commands that call for actions customized per device type. 422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */ 432918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimabstract class HdmiCecLocalDevice { 44092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static final String TAG = "HdmiCecLocalDevice"; 452918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1; 473e1564ee397ef833cba351153029317786f3d6bbTerry Heo private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2; 484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Timeout in millisecond for device clean up (5s). 494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Normal actions timeout is 2s but some of them would have several sequence of timeout. 504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private static final int DEVICE_CLEANUP_TIMEOUT = 5000; 513e1564ee397ef833cba351153029317786f3d6bbTerry Heo // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior. 523e1564ee397ef833cba351153029317786f3d6bbTerry Heo // When it expires, we can assume <User Control Release> is received. 533e1564ee397ef833cba351153029317786f3d6bbTerry Heo private static final int FOLLOWER_SAFETY_TIMEOUT = 550; 544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang protected final HdmiControlService mService; 562918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected final int mDeviceType; 572918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected int mAddress; 582918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected int mPreferredAddress; 5961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang protected HdmiDeviceInfo mDeviceInfo; 603e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE; 613e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected int mLastKeyRepeatCount = 0; 622918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 6372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim static class ActiveSource { 6472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress; 6572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int physicalAddress; 6672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 6743c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim public ActiveSource() { 6843c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim invalidate(); 6943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 7072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public ActiveSource(int logical, int physical) { 7172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim logicalAddress = logical; 7272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim physicalAddress = physical; 7372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 7404f813c9b3d1d15bd9462a728ab983f21d937281Jinsuk Kim public static ActiveSource of(ActiveSource source) { 7504f813c9b3d1d15bd9462a728ab983f21d937281Jinsuk Kim return new ActiveSource(source.logicalAddress, source.physicalAddress); 7604f813c9b3d1d15bd9462a728ab983f21d937281Jinsuk Kim } 7772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public static ActiveSource of(int logical, int physical) { 7872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return new ActiveSource(logical, physical); 7972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 8072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean isValid() { 8172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return HdmiUtils.isValidAddress(logicalAddress); 8272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 8343c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim public void invalidate() { 8443c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim logicalAddress = Constants.ADDR_INVALID; 8543c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim physicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; 8643c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 8772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean equals(int logical, int physical) { 8872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return logicalAddress == logical && physicalAddress == physical; 8972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 9072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @Override 9172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean equals(Object obj) { 9272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (obj instanceof ActiveSource) { 9372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource that = (ActiveSource) obj; 9472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return that.logicalAddress == logicalAddress && 9572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim that.physicalAddress == physicalAddress; 9672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 9772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return false; 9872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 9972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @Override 10072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public int hashCode() { 10172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return logicalAddress * 29 + physicalAddress; 10272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 103959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 104959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo public String toString() { 105959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo StringBuffer s = new StringBuffer(); 106959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo String logicalAddressString = (logicalAddress == Constants.ADDR_INVALID) 107959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo ? "invalid" : String.format("0x%02x", logicalAddress); 10804f813c9b3d1d15bd9462a728ab983f21d937281Jinsuk Kim s.append("(").append(logicalAddressString); 109959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo String physicalAddressString = (physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) 110959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo ? "invalid" : String.format("0x%04x", physicalAddress); 11104f813c9b3d1d15bd9462a728ab983f21d937281Jinsuk Kim s.append(", ").append(physicalAddressString).append(")"); 112959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo return s.toString(); 113959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 11472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 11579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Logical address of the active source. 11679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @GuardedBy("mLock") 11743c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim protected final ActiveSource mActiveSource = new ActiveSource(); 11879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 11979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Active routing path. Physical address of the active source but not all the time, such as 12079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // when the new active source does not claim itself to be one. Note that we don't keep 12179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}. 12279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @GuardedBy("mLock") 12379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private int mActiveRoutingPath; 12479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 12579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache(); 12679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected final Object mLock; 12779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 12879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // A collection of FeatureAction. 12979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Note that access to this collection should happen in service thread. 1305352081c662299b618335bf3024058fa04ef2dfdJungshik Jang private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>(); 13179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 132c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo private final Handler mHandler = new Handler () { 1334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 1344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void handleMessage(Message msg) { 1354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang switch (msg.what) { 1364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang case MSG_DISABLE_DEVICE_TIMEOUT: 1374fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang handleDisableDeviceTimeout(); 1384fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang break; 1393e1564ee397ef833cba351153029317786f3d6bbTerry Heo case MSG_USER_CONTROL_RELEASE_TIMEOUT: 1403e1564ee397ef833cba351153029317786f3d6bbTerry Heo handleUserControlReleased(); 1413e1564ee397ef833cba351153029317786f3d6bbTerry Heo break; 1424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }; 1454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang /** 1474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * A callback interface to get notified when all pending action is cleared. 1484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * It can be called when timeout happened. 1494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang */ 1504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang interface PendingActionClearedCallback { 1514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang void onCleared(HdmiCecLocalDevice device); 1524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang protected PendingActionClearedCallback mPendingActionClearedCallback; 1554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) { 1573ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService = service; 1582918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mDeviceType = deviceType; 159c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress = Constants.ADDR_UNREGISTERED; 16079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mLock = service.getServiceLock(); 1612918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1622918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1632918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Factory method that returns HdmiCecLocalDevice of corresponding type. 1643ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) { 1652918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim switch (deviceType) { 16661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang case HdmiDeviceInfo.DEVICE_TV: 1673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecLocalDeviceTv(service); 16861f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang case HdmiDeviceInfo.DEVICE_PLAYBACK: 1693ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecLocalDevicePlayback(service); 1702918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim default: 1712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return null; 1722918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1732918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1742918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 175a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1763ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void init() { 177a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 178af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim mPreferredAddress = getPreferredAddress(); 1797e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim mPendingActionClearedCallback = null; 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1812918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1828b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang /** 1833ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Called once a logical address of the local device is allocated. 1848b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang */ 185fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo protected abstract void onAddressAllocated(int logicalAddress, int reason); 1868b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 187092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 188af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim * Get the preferred logical address from system properties. 189af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim */ 190af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected abstract int getPreferredAddress(); 191af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 192af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim /** 193af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim * Set the preferred logical address to system properties. 194af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim */ 195af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected abstract void setPreferredAddress(int addr); 196af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 197af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim /** 1986e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * Returns true if the TV input associated with the CEC device is ready 1996e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * to accept further processing such as input switching. This is used 2006e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * to buffer certain CEC commands and process it later if the input is not 2016e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * ready yet. For other types of local devices(non-TV), this method returns 2026e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim * true by default to let the commands be processed right away. 2036e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim */ 2046e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim protected boolean isInputReady(int deviceId) { 2056e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim return true; 2066e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim } 2076e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim 2086e26f7f7b09dfd8495ec5478a7a4713dab346bc1Jinsuk Kim /** 209e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim * Returns true if the local device allows the system to be put to standby. 210e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim * The default implementation returns true. 211e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim */ 212e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim protected boolean canGoToStandby() { 213e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim return true; 214e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim } 215e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim 216e26d833c4a00bc7c1c23083f28ef891703e7e385Jinsuk Kim /** 217092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Dispatch incoming message. 218092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 219092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param message incoming message 220092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return true if consumed a message; otherwise, return false. 221092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 222a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 22325c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean dispatchMessage(HdmiCecMessage message) { 22479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 225092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int dest = message.getDestination(); 226c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (dest != mAddress && dest != Constants.ADDR_BROADCAST) { 227092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 228092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 22979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Cache incoming message. Note that it caches only white-listed one. 23079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecMessageCache.cacheMessage(message); 231092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return onMessage(message); 232092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 233092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 234a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 23560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected final boolean onMessage(HdmiCecMessage message) { 23679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 23779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (dispatchMessageToAction(message)) { 23879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 23979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 240092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang switch (message.getOpcode()) { 241c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 2428333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleActiveSource(message); 243c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_INACTIVE_SOURCE: 2448333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleInactiveSource(message); 245c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE: 2468333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleRequestActiveSource(message); 247c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GET_MENU_LANGUAGE: 248092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGetMenuLanguage(message); 249795415b57b7271a11d16ca42703251a325df1097Terry Heo case Constants.MESSAGE_SET_MENU_LANGUAGE: 250795415b57b7271a11d16ca42703251a325df1097Terry Heo return handleSetMenuLanguage(message); 251c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: 252092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGivePhysicalAddress(); 253c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_OSD_NAME: 254092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGiveOsdName(message); 255c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID: 256092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGiveDeviceVendorId(); 257c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GET_CEC_VERSION: 258092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGetCecVersion(message); 259c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: 26060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return handleReportPhysicalAddress(message); 261c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_ROUTING_CHANGE: 26292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return handleRoutingChange(message); 26364bafd9108b532102bc13c47966444b073c33fafYuncheol Heo case Constants.MESSAGE_ROUTING_INFORMATION: 26464bafd9108b532102bc13c47966444b073c33fafYuncheol Heo return handleRoutingInformation(message); 265c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_INITIATE_ARC: 26679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleInitiateArc(message); 267c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_TERMINATE_ARC: 26879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleTerminateArc(message); 269c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE: 27079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleSetSystemAudioMode(message); 271c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: 27279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleSystemAudioModeStatus(message); 273c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REPORT_AUDIO_STATUS: 2748fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return handleReportAudioStatus(message); 275c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_STANDBY: 27638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleStandby(message); 277c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_TEXT_VIEW_ON: 27838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleTextViewOn(message); 279c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_IMAGE_VIEW_ON: 28038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleImageViewOn(message); 281c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_USER_CONTROL_PRESSED: 28238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleUserControlPressed(message); 2833e1564ee397ef833cba351153029317786f3d6bbTerry Heo case Constants.MESSAGE_USER_CONTROL_RELEASED: 2843e1564ee397ef833cba351153029317786f3d6bbTerry Heo return handleUserControlReleased(); 285c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SET_STREAM_PATH: 28638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleSetStreamPath(message); 287c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS: 28838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleGiveDevicePowerStatus(message); 2893e1564ee397ef833cba351153029317786f3d6bbTerry Heo case Constants.MESSAGE_MENU_REQUEST: 290184b124ec22a796327642e3546d366179e693f07Yuncheol Heo return handleMenuRequest(message); 291184b124ec22a796327642e3546d366179e693f07Yuncheol Heo case Constants.MESSAGE_MENU_STATUS: 292184b124ec22a796327642e3546d366179e693f07Yuncheol Heo return handleMenuStatus(message); 293119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim case Constants.MESSAGE_VENDOR_COMMAND: 294119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return handleVendorCommand(message); 295119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID: 296119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return handleVendorCommandWithId(message); 2978f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang case Constants.MESSAGE_SET_OSD_NAME: 2988f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return handleSetOsdName(message); 299b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang case Constants.MESSAGE_RECORD_TV_SCREEN: 300b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return handleRecordTvScreen(message); 301e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case Constants.MESSAGE_TIMER_CLEARED_STATUS: 302e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return handleTimerClearedStatus(message); 3034480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang case Constants.MESSAGE_REPORT_POWER_STATUS: 3044480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return handleReportPowerStatus(message); 3054480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang case Constants.MESSAGE_TIMER_STATUS: 3064480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return handleTimerStatus(message); 3074480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang case Constants.MESSAGE_RECORD_STATUS: 3084480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return handleRecordStatus(message); 309092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang default: 310092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 311092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 312092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 313092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 314a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 31579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean dispatchMessageToAction(HdmiCecMessage message) { 316a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 3175352081c662299b618335bf3024058fa04ef2dfdJungshik Jang boolean processed = false; 3185352081c662299b618335bf3024058fa04ef2dfdJungshik Jang // Use copied action list in that processCommand may remove itself. 3195352081c662299b618335bf3024058fa04ef2dfdJungshik Jang for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) { 3205352081c662299b618335bf3024058fa04ef2dfdJungshik Jang // Iterates all actions to check whether incoming message is consumed. 3215352081c662299b618335bf3024058fa04ef2dfdJungshik Jang boolean result = action.processCommand(message); 3225352081c662299b618335bf3024058fa04ef2dfdJungshik Jang processed = processed || result; 32379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 3245352081c662299b618335bf3024058fa04ef2dfdJungshik Jang return processed; 32579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 32679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 327a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 328092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGivePhysicalAddress() { 32979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 33079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 331092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int physicalAddress = mService.getPhysicalAddress(); 332092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 333092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, physicalAddress, mDeviceType); 334092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 335092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 336092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 337092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 338a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 339092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGiveDeviceVendorId() { 34079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 341092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int vendorId = mService.getVendorId(); 342092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 343092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, vendorId); 344092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 346092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 347092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 348a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 349092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetCecVersion(HdmiCecMessage message) { 35079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int version = mService.getCecVersion(); 352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(), 353092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang message.getSource(), version); 354092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 355092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 356092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 357092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 358a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3598333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleActiveSource(HdmiCecMessage message) { 3608333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3618333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3628333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3638333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3648333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleInactiveSource(HdmiCecMessage message) { 3658333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3668333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3678333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3688333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3698333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleRequestActiveSource(HdmiCecMessage message) { 3708333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3718333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3728333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3738333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 374092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetMenuLanguage(HdmiCecMessage message) { 37579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 376092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString()); 3776aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // 'return false' will cause to reply with <Feature Abort>. 3786aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo return false; 379092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 380092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 381a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 382795415b57b7271a11d16ca42703251a325df1097Terry Heo protected boolean handleSetMenuLanguage(HdmiCecMessage message) { 383795415b57b7271a11d16ca42703251a325df1097Terry Heo assertRunOnServiceThread(); 384795415b57b7271a11d16ca42703251a325df1097Terry Heo Slog.w(TAG, "Only Playback device can handle <Set Menu Language>:" + message.toString()); 385795415b57b7271a11d16ca42703251a325df1097Terry Heo // 'return false' will cause to reply with <Feature Abort>. 386795415b57b7271a11d16ca42703251a325df1097Terry Heo return false; 387795415b57b7271a11d16ca42703251a325df1097Terry Heo } 388795415b57b7271a11d16ca42703251a325df1097Terry Heo 389795415b57b7271a11d16ca42703251a325df1097Terry Heo @ServiceThreadOnly 390092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGiveOsdName(HdmiCecMessage message) { 39179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 392092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // Note that since this method is called after logical address allocation is done, 393092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // mDeviceInfo should not be null. 394092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand( 395092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, message.getSource(), mDeviceInfo.getDisplayName()); 396092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang if (cecMessage != null) { 397092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 398092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } else { 399092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName()); 400092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 401092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 402092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 403092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 40492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim protected boolean handleRoutingChange(HdmiCecMessage message) { 40592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 40692b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 40792b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 40864bafd9108b532102bc13c47966444b073c33fafYuncheol Heo protected boolean handleRoutingInformation(HdmiCecMessage message) { 40964bafd9108b532102bc13c47966444b073c33fafYuncheol Heo return false; 41064bafd9108b532102bc13c47966444b073c33fafYuncheol Heo } 41164bafd9108b532102bc13c47966444b073c33fafYuncheol Heo 41260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { 41360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 41460cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 41560cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 41679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { 41779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 41879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 41979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 42079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { 42179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 42279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 42379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 42479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleTerminateArc(HdmiCecMessage message) { 42579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 42679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 42779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 42879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleInitiateArc(HdmiCecMessage message) { 42979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 4308fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 4318fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 4328fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang protected boolean handleReportAudioStatus(HdmiCecMessage message) { 4338fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return false; 43479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 43579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 436a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 43738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleStandby(HdmiCecMessage message) { 43838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 43938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Seq #12 4404d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (mService.isControlEnabled() && !mService.isProhibitMode() 44138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo && mService.isPowerOnOrTransient()) { 44238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.standby(); 44338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 44438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 44538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 44638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 44738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 44838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 44938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleUserControlPressed(HdmiCecMessage message) { 45038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 4513e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT); 45238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) { 45338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.standby(); 45438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 45538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { 45638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.wakeUp(); 45738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 45838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 4593e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4603e1564ee397ef833cba351153029317786f3d6bbTerry Heo final long downTime = SystemClock.uptimeMillis(); 4613e1564ee397ef833cba351153029317786f3d6bbTerry Heo final byte[] params = message.getParams(); 46273483b6bc9046cbb7a54748c31ee724358a631efJungshik Jang final int keycode = HdmiCecKeycode.cecKeycodeAndParamsToAndroidKey(params); 4633e1564ee397ef833cba351153029317786f3d6bbTerry Heo int keyRepeatCount = 0; 4643e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4653e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (keycode == mLastKeycode) { 4663e1564ee397ef833cba351153029317786f3d6bbTerry Heo keyRepeatCount = mLastKeyRepeatCount + 1; 4673e1564ee397ef833cba351153029317786f3d6bbTerry Heo } else { 4683e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(downTime, KeyEvent.ACTION_UP, mLastKeycode, 0); 4693e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4703e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4713e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeycode = keycode; 4723e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeyRepeatCount = keyRepeatCount; 4733e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4743e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (keycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4753e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(downTime, KeyEvent.ACTION_DOWN, keycode, keyRepeatCount); 4763e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_USER_CONTROL_RELEASE_TIMEOUT), 4773e1564ee397ef833cba351153029317786f3d6bbTerry Heo FOLLOWER_SAFETY_TIMEOUT); 4783e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 4793e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4803e1564ee397ef833cba351153029317786f3d6bbTerry Heo return false; 4813e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4823e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4833e1564ee397ef833cba351153029317786f3d6bbTerry Heo @ServiceThreadOnly 4843e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected boolean handleUserControlReleased() { 4853e1564ee397ef833cba351153029317786f3d6bbTerry Heo assertRunOnServiceThread(); 4863e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT); 4873e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeyRepeatCount = 0; 4883e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4893e1564ee397ef833cba351153029317786f3d6bbTerry Heo final long upTime = SystemClock.uptimeMillis(); 4903e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(upTime, KeyEvent.ACTION_UP, mLastKeycode, 0); 4913e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE; 4923e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 4933e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 49438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 49538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 49638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 4973e1564ee397ef833cba351153029317786f3d6bbTerry Heo static void injectKeyEvent(long time, int action, int keycode, int repeat) { 4983e1564ee397ef833cba351153029317786f3d6bbTerry Heo KeyEvent keyEvent = KeyEvent.obtain(time, time, action, keycode, 4993e1564ee397ef833cba351153029317786f3d6bbTerry Heo repeat, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 5003e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputDevice.SOURCE_HDMI, null); 5013e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputManager.getInstance().injectInputEvent(keyEvent, 5023e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 5033e1564ee397ef833cba351153029317786f3d6bbTerry Heo keyEvent.recycle(); 5043e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 5053e1564ee397ef833cba351153029317786f3d6bbTerry Heo 50625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) { 50738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo byte[] params = message.getParams(); 508c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED 509210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER 510210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION 511210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); 51238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 51338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 51425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) { 51538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo byte[] params = message.getParams(); 516c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED 517210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER 518210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION 519210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); 52038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 52138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 52238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleTextViewOn(HdmiCecMessage message) { 52338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 52438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 52538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 52638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleImageViewOn(HdmiCecMessage message) { 52738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 52838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 52938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 53038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleSetStreamPath(HdmiCecMessage message) { 53138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 53238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 53338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 53438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) { 53538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus( 53638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mAddress, message.getSource(), mService.getPowerStatus())); 53738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 53838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 53938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 540184b124ec22a796327642e3546d366179e693f07Yuncheol Heo protected boolean handleMenuRequest(HdmiCecMessage message) { 5413e1564ee397ef833cba351153029317786f3d6bbTerry Heo // Always report menu active to receive Remote Control. 5423e1564ee397ef833cba351153029317786f3d6bbTerry Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus( 5433e1564ee397ef833cba351153029317786f3d6bbTerry Heo mAddress, message.getSource(), Constants.MENU_STATE_ACTIVATED)); 5443e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 5453e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 5463e1564ee397ef833cba351153029317786f3d6bbTerry Heo 547184b124ec22a796327642e3546d366179e693f07Yuncheol Heo protected boolean handleMenuStatus(HdmiCecMessage message) { 548184b124ec22a796327642e3546d366179e693f07Yuncheol Heo return false; 549184b124ec22a796327642e3546d366179e693f07Yuncheol Heo } 550184b124ec22a796327642e3546d366179e693f07Yuncheol Heo 551119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim protected boolean handleVendorCommand(HdmiCecMessage message) { 5520608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(), 5530608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo message.getDestination(), message.getParams(), false)) { 554d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim // Vendor command listener may not have been registered yet. Respond with 555d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim // <Feature Abort> [NOT_IN_CORRECT_MODE] so that the sender can try again later. 556d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); 557d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 558119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return true; 559119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 560119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 561119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim protected boolean handleVendorCommandWithId(HdmiCecMessage message) { 562119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim byte[] params = message.getParams(); 563119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim int vendorId = HdmiUtils.threeBytesToInt(params); 564119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (vendorId == mService.getVendorId()) { 5650608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(), 5660608b9328b1c2f804ffb2d4165c34383d34bde2aYuncheol Heo message.getDestination(), params, true)) { 567d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); 568d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 569119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else if (message.getDestination() != Constants.ADDR_BROADCAST && 570119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim message.getSource() != Constants.ADDR_UNREGISTERED) { 571119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>"); 5726aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE); 573119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 574119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.v(TAG, "Wrong broadcast vendor command. Ignoring"); 575119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 576119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return true; 577119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 578119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 579d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim protected void sendStandby(int deviceId) { 580d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim // Do nothing. 581d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim } 582d4a94db1cd44a536d535de890a0a14919a39a0dcJinsuk Kim 5838f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang protected boolean handleSetOsdName(HdmiCecMessage message) { 5848f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang // The default behavior of <Set Osd Name> is doing nothing. 5858f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 5868f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 5878f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 588b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang protected boolean handleRecordTvScreen(HdmiCecMessage message) { 58925c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo // The default behavior of <Record TV Screen> is replying <Feature Abort> with 59025c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo // "Cannot provide source". 5916aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mService.maySendFeatureAbortCommand(message, Constants.ABORT_CANNOT_PROVIDE_SOURCE); 592b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 593b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 594b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 595e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang protected boolean handleTimerClearedStatus(HdmiCecMessage message) { 596e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return false; 597e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 598e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 5994480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleReportPowerStatus(HdmiCecMessage message) { 6004480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return false; 6014480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6024480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6034480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleTimerStatus(HdmiCecMessage message) { 6044480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return false; 6054480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6064480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 6074480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang protected boolean handleRecordStatus(HdmiCecMessage message) { 6084480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang return false; 6094480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang } 6104480efa05aa5dd44f1432c3260be263546daf838Jungshik Jang 61138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 612fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final void handleAddressAllocated(int logicalAddress, int reason) { 61379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 6143ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress = mPreferredAddress = logicalAddress; 615fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onAddressAllocated(logicalAddress, reason); 616af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim setPreferredAddress(logicalAddress); 6171a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 6181a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 619b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo int getType() { 620b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo return mDeviceType; 621b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo } 622b502186ab34a4de40f1d98591a0c5d8b4eac76e2Yuncheol Heo 623a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 62461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo() { 62579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 6261a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang return mDeviceInfo; 6271a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 6281a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 629a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 63061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void setDeviceInfo(HdmiDeviceInfo info) { 63179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 6321a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang mDeviceInfo = info; 6331a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 6341a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 6352918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Returns true if the logical address is same as the argument. 636a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6372918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim boolean isAddressOf(int addr) { 63879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 6392918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return addr == mAddress; 6402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 6412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 6422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Resets the logical address to unregistered(15), meaning the logical device is invalid. 643a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 6442918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim void clearAddress() { 64579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 646c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress = Constants.ADDR_UNREGISTERED; 6472918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 6482918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 649a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 650b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang void addAndStartAction(final HdmiCecFeatureAction action) { 65179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 6526f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim mActions.add(action); 653a5445ce992a4e8ac5252975acedf3e5aec53867aJinsuk Kim if (mService.isPowerStandby()) { 6546f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim Slog.i(TAG, "Not ready to start action. Queued for deferred start:" + action); 65538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 65638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 65779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang action.start(); 65879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 65979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 6606f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim @ServiceThreadOnly 6616f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim void startQueuedActions() { 6626f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim assertRunOnServiceThread(); 6636f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim for (HdmiCecFeatureAction action : mActions) { 6646f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim if (!action.started()) { 6656f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim Slog.i(TAG, "Starting queued action:" + action); 6666f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim action.start(); 6676f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 6686f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 6696f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim } 6706f87b4e6b6db76cb32d449ad1fdf1946ff4e96f7Jinsuk Kim 67179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // See if we have an action of a given type in progress. 672a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 673b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> boolean hasAction(final Class<T> clazz) { 67479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 675b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang for (HdmiCecFeatureAction action : mActions) { 67679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action.getClass().equals(clazz)) { 67779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 67879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 67979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 68079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 68179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 68279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 68379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Returns all actions matched with given class type. 684a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 685b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) { 68679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 68743c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim List<T> actions = Collections.<T>emptyList(); 688b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang for (HdmiCecFeatureAction action : mActions) { 68979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action.getClass().equals(clazz)) { 69043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim if (actions.isEmpty()) { 69143c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim actions = new ArrayList<T>(); 69243c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 69379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang actions.add((T) action); 69479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 69579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 69679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return actions; 69779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 69879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 69979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 700b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * Remove the given {@link HdmiCecFeatureAction} object from the action queue. 70179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 702b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * @param action {@link HdmiCecFeatureAction} to remove 70379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 704a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 705b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang void removeAction(final HdmiCecFeatureAction action) { 70679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 707c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 70879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mActions.remove(action); 70938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 71079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 71179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 71279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Remove all actions matched with the given Class type. 713a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 714b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) { 715a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 71679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeActionExcept(clazz, null); 71779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 71879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 71979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Remove all actions matched with the given Class type besides |exception|. 720a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 721b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz, 722b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang final HdmiCecFeatureAction exception) { 72379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 724b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang Iterator<HdmiCecFeatureAction> iter = mActions.iterator(); 72579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang while (iter.hasNext()) { 726b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang HdmiCecFeatureAction action = iter.next(); 72779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action != exception && action.getClass().equals(clazz)) { 728c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 729c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo iter.remove(); 73079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 73379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 73538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected void checkIfPendingActionsCleared() { 7364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mActions.isEmpty() && mPendingActionClearedCallback != null) { 73726ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo PendingActionClearedCallback callback = mPendingActionClearedCallback; 73826ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo // To prevent from calling the callback again during handling the callback itself. 73926ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo mPendingActionClearedCallback = null; 74026ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo callback.onCleared(this); 74138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 74238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 7434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 74479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected void assertRunOnServiceThread() { 74579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (Looper.myLooper() != mService.getServiceLooper()) { 74679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang throw new IllegalStateException("Should run on service thread."); 74779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 74879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 74979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 750e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim void setAutoDeviceOff(boolean enabled) { 751e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim } 752e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim 75379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 75479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Called when a hot-plug event issued. 75579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 75679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param portId id of port where a hot-plug event happened 75779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param connected whether to connected or not on the event 75879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 75979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void onHotplug(int portId, boolean connected) { 76079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 76179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 76279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final HdmiControlService getService() { 76379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService; 76479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 76579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 766a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 76779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final boolean isConnectedToArcPort(int path) { 768a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 76979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.isConnectedToArcPort(path); 77079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 77179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 77272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource getActiveSource() { 77379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 77479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mActiveSource; 77579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 77679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 77779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 77872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void setActiveSource(ActiveSource newActive) { 77972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(newActive.logicalAddress, newActive.physicalAddress); 78072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 78172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 78261f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void setActiveSource(HdmiDeviceInfo info) { 78372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress()); 78472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 78572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 78672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void setActiveSource(int logicalAddress, int physicalAddress) { 7878333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 78872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mActiveSource.logicalAddress = logicalAddress; 78972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mActiveSource.physicalAddress = physicalAddress; 7908333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 791e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mService.setLastInputForMhl(Constants.INVALID_PORT_ID); 7928333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 7938333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 79479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang int getActivePath() { 79579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 79679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mActiveRoutingPath; 79779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 79879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 79979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 8008333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void setActivePath(int path) { 8018333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 8028333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mActiveRoutingPath = path; 8038333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 804867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mService.setActivePortId(pathToPortId(path)); 8058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 8068333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 80779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 808a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Returns the ID of the active HDMI port. The active port is the one that has the active 809a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * routing path connected to it directly or indirectly under the device hierarchy. 81079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 811a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim int getActivePortId() { 81279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 81379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.pathToPortId(mActiveRoutingPath); 81479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 81579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 81679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 817a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 818a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Update the active port. 819a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * 820a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * @param portId the new active port id 821a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 822a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim void setActivePortId(int portId) { 823867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang // We update active routing path instead, since we get the active port id from 824867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang // the active routing path. 825867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang setActivePath(mService.portIdToPath(portId)); 826a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 827a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 828a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 82979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecMessageCache getCecMessageCache() { 83079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 83179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mCecMessageCache; 83279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 83379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 834a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 83579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang int pathToPortId(int newPath) { 83679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 83779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.pathToPortId(newPath); 83879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 83938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 84038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 8414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * Called when the system goes to standby mode. 84238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * 84338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * @param initiatedByCec true if this power sequence is initiated 844b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * by the reception the CEC messages like <Standby> 845e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim * @param standbyAction Intent action that drives the standby process, 846e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim * either {@link HdmiControlService#STANDBY_SCREEN_OFF} or 847e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim * {@link HdmiControlService#STANDBY_SHUTDOWN} 84838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 849e6e8f3d589f42393cf02a2bd766d678d80dad874Jinsuk Kim protected void onStandby(boolean initiatedByCec, int standbyAction) {} 85038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 85138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 8524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * Disable device. {@code callback} is used to get notified when all pending 8534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * actions are completed or timeout is issued. 85438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * 8554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * @param initiatedByCec true if this sequence is initiated 856b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * by the reception the CEC messages like <Standby> 8577e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim * @param originalCallback callback interface to get notified when all pending actions are 858b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * cleared 85938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 860b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang protected void disableDevice(boolean initiatedByCec, 8617e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim final PendingActionClearedCallback originalCallback) { 862b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang mPendingActionClearedCallback = new PendingActionClearedCallback() { 863b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang @Override 864b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang public void onCleared(HdmiCecLocalDevice device) { 865b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT); 8667e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim originalCallback.onCleared(device); 867b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang } 868b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang }; 8694fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_DISABLE_DEVICE_TIMEOUT), 8704fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang DEVICE_CLEANUP_TIMEOUT); 8714fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 8724fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 8734fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 8744fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void handleDisableDeviceTimeout() { 8754fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 8764fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 8774fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // If all actions are not cleared in DEVICE_CLEANUP_TIMEOUT, enforce to finish them. 8784fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // onCleard will be called at the last action's finish method. 879b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang Iterator<HdmiCecFeatureAction> iter = mActions.iterator(); 8804fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang while (iter.hasNext()) { 881b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang HdmiCecFeatureAction action = iter.next(); 882c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 8834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang iter.remove(); 8844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 8857e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim if (mPendingActionClearedCallback != null) { 8867e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim mPendingActionClearedCallback.onCleared(this); 8877e4b480a0bf9f93a428f7c46bfea77ebfdb92d40Jinsuk Kim } 8884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 889c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim 890c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim /** 891c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * Send a key event to other device. 892c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * 8934fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * @param keyCode key code defined in {@link android.view.KeyEvent} 894c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * @param isPressed {@code true} for key down event 895c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim */ 896c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim protected void sendKeyEvent(int keyCode, boolean isPressed) { 897c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "sendKeyEvent not implemented"); 898c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim } 899959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 9002e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) { 9012e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlPressed( 9022e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mAddress, targetAddress, cecKeycode)); 9032e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlReleased( 9042e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang mAddress, targetAddress)); 9052e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang } 9062e8f1b6399089626b4f0249427626ba6e63a62efJungshik Jang 907959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo /** 908959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo * Dump internal status of HdmiCecLocalDevice object. 909959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo */ 910959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(final IndentingPrintWriter pw) { 911959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mDeviceType: " + mDeviceType); 912959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAddress: " + mAddress); 913959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPreferredAddress: " + mPreferredAddress); 914959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mDeviceInfo: " + mDeviceInfo); 915959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mActiveSource: " + mActiveSource); 916959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath)); 917959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 9182918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim} 919