HdmiCecLocalDevice.java revision 959d2db12c7c6a06465af1251bc4cece580a72a3
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.LinkedList; 3879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jangimport java.util.List; 3979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 402918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim/** 412918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * Class that models a logical CEC device hosted in this system. Handles initialization, 422918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim * CEC commands that call for actions customized per device type. 432918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim */ 442918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kimabstract class HdmiCecLocalDevice { 45092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang private static final String TAG = "HdmiCecLocalDevice"; 462918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1; 483e1564ee397ef833cba351153029317786f3d6bbTerry Heo private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2; 494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Timeout in millisecond for device clean up (5s). 504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // Normal actions timeout is 2s but some of them would have several sequence of timeout. 514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private static final int DEVICE_CLEANUP_TIMEOUT = 5000; 523e1564ee397ef833cba351153029317786f3d6bbTerry Heo // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior. 533e1564ee397ef833cba351153029317786f3d6bbTerry Heo // When it expires, we can assume <User Control Release> is received. 543e1564ee397ef833cba351153029317786f3d6bbTerry Heo private static final int FOLLOWER_SAFETY_TIMEOUT = 550; 554fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 563ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang protected final HdmiControlService mService; 572918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected final int mDeviceType; 582918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected int mAddress; 592918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim protected int mPreferredAddress; 6061f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang protected HdmiDeviceInfo mDeviceInfo; 613e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE; 623e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected int mLastKeyRepeatCount = 0; 632918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 6472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim static class ActiveSource { 6572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int logicalAddress; 6672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim int physicalAddress; 6772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 6843c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim public ActiveSource() { 6943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim invalidate(); 7043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 7172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public ActiveSource(int logical, int physical) { 7272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim logicalAddress = logical; 7372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim physicalAddress = physical; 7472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 7572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public static ActiveSource of(int logical, int physical) { 7672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return new ActiveSource(logical, physical); 7772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 7872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean isValid() { 7972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return HdmiUtils.isValidAddress(logicalAddress); 8072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 8143c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim public void invalidate() { 8243c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim logicalAddress = Constants.ADDR_INVALID; 8343c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim physicalAddress = Constants.INVALID_PHYSICAL_ADDRESS; 8443c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 8572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean equals(int logical, int physical) { 8672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return logicalAddress == logical && physicalAddress == physical; 8772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 8872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @Override 8972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public boolean equals(Object obj) { 9072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim if (obj instanceof ActiveSource) { 9172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource that = (ActiveSource) obj; 9272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return that.logicalAddress == logicalAddress && 9372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim that.physicalAddress == physicalAddress; 9472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 9572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return false; 9672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 9772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim @Override 9872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim public int hashCode() { 9972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim return logicalAddress * 29 + physicalAddress; 10072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 101959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo @Override 102959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo public String toString() { 103959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo StringBuffer s = new StringBuffer(); 104959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo String logicalAddressString = (logicalAddress == Constants.ADDR_INVALID) 105959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo ? "invalid" : String.format("0x%02x", logicalAddress); 106959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo s.append("logical_address: ").append(logicalAddressString); 107959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo String physicalAddressString = (physicalAddress == Constants.INVALID_PHYSICAL_ADDRESS) 108959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo ? "invalid" : String.format("0x%04x", physicalAddress); 109959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo s.append(", physical_address: ").append(physicalAddressString); 110959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo return s.toString(); 111959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 11272b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 11379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Logical address of the active source. 11479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @GuardedBy("mLock") 11543c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim protected final ActiveSource mActiveSource = new ActiveSource(); 11679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 11779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Active routing path. Physical address of the active source but not all the time, such as 11879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // when the new active source does not claim itself to be one. Note that we don't keep 11979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // the active port id (or active input) since it can be gotten by {@link #pathToPortId(int)}. 12079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang @GuardedBy("mLock") 12179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private int mActiveRoutingPath; 12279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 12379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected final HdmiCecMessageCache mCecMessageCache = new HdmiCecMessageCache(); 12479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected final Object mLock; 12579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 12679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // A collection of FeatureAction. 12779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Note that access to this collection should happen in service thread. 128b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>(); 12979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 130c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo private final Handler mHandler = new Handler () { 1314fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @Override 1324fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang public void handleMessage(Message msg) { 1334fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang switch (msg.what) { 1344fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang case MSG_DISABLE_DEVICE_TIMEOUT: 1354fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang handleDisableDeviceTimeout(); 1364fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang break; 1373e1564ee397ef833cba351153029317786f3d6bbTerry Heo case MSG_USER_CONTROL_RELEASE_TIMEOUT: 1383e1564ee397ef833cba351153029317786f3d6bbTerry Heo handleUserControlReleased(); 1393e1564ee397ef833cba351153029317786f3d6bbTerry Heo break; 1404fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1414fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1424fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang }; 1434fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1444fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang /** 1454fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * A callback interface to get notified when all pending action is cleared. 1464fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * It can be called when timeout happened. 1474fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang */ 1484fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang interface PendingActionClearedCallback { 1494fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang void onCleared(HdmiCecLocalDevice device); 1504fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 1514fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1524fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang protected PendingActionClearedCallback mPendingActionClearedCallback; 1534fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 1543ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang protected HdmiCecLocalDevice(HdmiControlService service, int deviceType) { 1553ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mService = service; 1562918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim mDeviceType = deviceType; 157c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress = Constants.ADDR_UNREGISTERED; 15879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mLock = service.getServiceLock(); 1592918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1602918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1612918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Factory method that returns HdmiCecLocalDevice of corresponding type. 1623ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang static HdmiCecLocalDevice create(HdmiControlService service, int deviceType) { 1632918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim switch (deviceType) { 16461f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang case HdmiDeviceInfo.DEVICE_TV: 1653ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecLocalDeviceTv(service); 16661f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang case HdmiDeviceInfo.DEVICE_PLAYBACK: 1673ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang return new HdmiCecLocalDevicePlayback(service); 1682918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim default: 1692918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return null; 1702918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 1722918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 173a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 1743ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang void init() { 175a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 176af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim mPreferredAddress = getPreferredAddress(); 1773ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang } 1782918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 1798b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang /** 1803ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang * Called once a logical address of the local device is allocated. 1818b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang */ 182fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo protected abstract void onAddressAllocated(int logicalAddress, int reason); 1838b308d93c8fdcc7304b33d9b445ae3807eae97c8Jungshik Jang 184092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang /** 185af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim * Get the preferred logical address from system properties. 186af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim */ 187af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected abstract int getPreferredAddress(); 188af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 189af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim /** 190af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim * Set the preferred logical address to system properties. 191af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim */ 192af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim protected abstract void setPreferredAddress(int addr); 193af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim 194af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim /** 195092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * Dispatch incoming message. 196092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * 197092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @param message incoming message 198092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang * @return true if consumed a message; otherwise, return false. 199092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang */ 200a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 20125c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo boolean dispatchMessage(HdmiCecMessage message) { 20279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 203092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int dest = message.getDestination(); 204c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim if (dest != mAddress && dest != Constants.ADDR_BROADCAST) { 205092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 206092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 20779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Cache incoming message. Note that it caches only white-listed one. 20879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mCecMessageCache.cacheMessage(message); 209092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return onMessage(message); 210092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 211092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 212a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 21360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected final boolean onMessage(HdmiCecMessage message) { 21479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 21579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (dispatchMessageToAction(message)) { 21679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 21779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 218092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang switch (message.getOpcode()) { 219c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_ACTIVE_SOURCE: 2208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleActiveSource(message); 221c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_INACTIVE_SOURCE: 2228333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleInactiveSource(message); 223c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REQUEST_ACTIVE_SOURCE: 2248333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return handleRequestActiveSource(message); 225c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GET_MENU_LANGUAGE: 226092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGetMenuLanguage(message); 227c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: 228092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGivePhysicalAddress(); 229c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_OSD_NAME: 230092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGiveOsdName(message); 231c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID: 232092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGiveDeviceVendorId(); 233c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GET_CEC_VERSION: 234092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return handleGetCecVersion(message); 235c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: 23660cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return handleReportPhysicalAddress(message); 237c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_ROUTING_CHANGE: 23892b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return handleRoutingChange(message); 23964bafd9108b532102bc13c47966444b073c33fafYuncheol Heo case Constants.MESSAGE_ROUTING_INFORMATION: 24064bafd9108b532102bc13c47966444b073c33fafYuncheol Heo return handleRoutingInformation(message); 241c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_INITIATE_ARC: 24279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleInitiateArc(message); 243c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_TERMINATE_ARC: 24479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleTerminateArc(message); 245c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SET_SYSTEM_AUDIO_MODE: 24679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleSetSystemAudioMode(message); 247c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: 24879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return handleSystemAudioModeStatus(message); 249c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_REPORT_AUDIO_STATUS: 2508fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return handleReportAudioStatus(message); 251c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_STANDBY: 25238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleStandby(message); 253c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_TEXT_VIEW_ON: 25438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleTextViewOn(message); 255c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_IMAGE_VIEW_ON: 25638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleImageViewOn(message); 257c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_USER_CONTROL_PRESSED: 25838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleUserControlPressed(message); 2593e1564ee397ef833cba351153029317786f3d6bbTerry Heo case Constants.MESSAGE_USER_CONTROL_RELEASED: 2603e1564ee397ef833cba351153029317786f3d6bbTerry Heo return handleUserControlReleased(); 261c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_SET_STREAM_PATH: 26238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleSetStreamPath(message); 263c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS: 26438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return handleGiveDevicePowerStatus(message); 2653e1564ee397ef833cba351153029317786f3d6bbTerry Heo case Constants.MESSAGE_MENU_REQUEST: 2663e1564ee397ef833cba351153029317786f3d6bbTerry Heo return handleGiveDeviceMenuStatus(message); 267119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim case Constants.MESSAGE_VENDOR_COMMAND: 268119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return handleVendorCommand(message); 269119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID: 270119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return handleVendorCommandWithId(message); 2718f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang case Constants.MESSAGE_SET_OSD_NAME: 2728f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return handleSetOsdName(message); 273b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang case Constants.MESSAGE_RECORD_TV_SCREEN: 274b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return handleRecordTvScreen(message); 275e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang case Constants.MESSAGE_TIMER_CLEARED_STATUS: 276e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return handleTimerClearedStatus(message); 277092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang default: 278092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return false; 279092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 280092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 281092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 282a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 28379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang private boolean dispatchMessageToAction(HdmiCecMessage message) { 284a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 285b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang for (HdmiCecFeatureAction action : mActions) { 28679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action.processCommand(message)) { 28779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 28879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 28979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 29079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 29179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 29279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 293a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 294092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGivePhysicalAddress() { 29579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 29679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 297092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int physicalAddress = mService.getPhysicalAddress(); 298092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( 299092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, physicalAddress, mDeviceType); 300092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 301092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 302092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 303092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 304a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 305092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGiveDeviceVendorId() { 30679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 307092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int vendorId = mService.getVendorId(); 308092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( 309092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, vendorId); 310092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 311092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 312092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 313092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 314a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 315092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetCecVersion(HdmiCecMessage message) { 31679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 317092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang int version = mService.getCecVersion(); 318092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildCecVersion(message.getDestination(), 319092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang message.getSource(), version); 320092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 321092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 322092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 323092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 324a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 3258333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleActiveSource(HdmiCecMessage message) { 3268333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3278333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3288333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3298333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3308333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleInactiveSource(HdmiCecMessage message) { 3318333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3328333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3338333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3348333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 3358333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim protected boolean handleRequestActiveSource(HdmiCecMessage message) { 3368333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim return false; 3378333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 3388333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 3398333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim @ServiceThreadOnly 340092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGetMenuLanguage(HdmiCecMessage message) { 34179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 342092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Only TV can handle <Get Menu Language>:" + message.toString()); 3436aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo // 'return false' will cause to reply with <Feature Abort>. 3446aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo return false; 345092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 346092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 347a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 348092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang protected boolean handleGiveOsdName(HdmiCecMessage message) { 34979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 350092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // Note that since this method is called after logical address allocation is done, 351092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang // mDeviceInfo should not be null. 352092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildSetOsdNameCommand( 353092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mAddress, message.getSource(), mDeviceInfo.getDisplayName()); 354092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang if (cecMessage != null) { 355092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang mService.sendCecCommand(cecMessage); 356092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } else { 357092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang Slog.w(TAG, "Failed to build <Get Osd Name>:" + mDeviceInfo.getDisplayName()); 358092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 359092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang return true; 360092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang } 361092b445ef898e3c1e5b2918b554480940f0f5a28Jungshik Jang 36292b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim protected boolean handleRoutingChange(HdmiCecMessage message) { 36392b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim return false; 36492b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim } 36592b77cf9cbf512e7141cad6fef5a38d0682dde43Jinsuk Kim 36664bafd9108b532102bc13c47966444b073c33fafYuncheol Heo protected boolean handleRoutingInformation(HdmiCecMessage message) { 36764bafd9108b532102bc13c47966444b073c33fafYuncheol Heo return false; 36864bafd9108b532102bc13c47966444b073c33fafYuncheol Heo } 36964bafd9108b532102bc13c47966444b073c33fafYuncheol Heo 37060cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang protected boolean handleReportPhysicalAddress(HdmiCecMessage message) { 37160cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang return false; 37260cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang } 37360cffce420db4c3395f86d3b9bb36003adf26f5dJungshik Jang 37479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) { 37579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 37679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 37779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 37879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleSetSystemAudioMode(HdmiCecMessage message) { 37979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 38079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 38179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 38279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleTerminateArc(HdmiCecMessage message) { 38379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 38479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 38579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 38679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected boolean handleInitiateArc(HdmiCecMessage message) { 38779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 3888fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang } 3898fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang 3908fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang protected boolean handleReportAudioStatus(HdmiCecMessage message) { 3918fa36b110be29d92a9aba070fa4666eefb14b584Jungshik Jang return false; 39279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 39379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 394a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 39538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleStandby(HdmiCecMessage message) { 39638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 39738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo // Seq #12 3984d43d93743222311c6377d4904c19ccb93699d3bJinsuk Kim if (mService.isControlEnabled() && !mService.isProhibitMode() 39938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo && mService.isPowerOnOrTransient()) { 40038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.standby(); 40138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 40238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 40338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 40438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 40538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 40638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 40738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleUserControlPressed(HdmiCecMessage message) { 40838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo assertRunOnServiceThread(); 4093e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT); 41038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) { 41138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.standby(); 41238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 41338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } else if (mService.isPowerStandbyOrTransient() && isPowerOnOrToggleCommand(message)) { 41438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.wakeUp(); 41538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 41638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 4173e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4183e1564ee397ef833cba351153029317786f3d6bbTerry Heo final long downTime = SystemClock.uptimeMillis(); 4193e1564ee397ef833cba351153029317786f3d6bbTerry Heo final byte[] params = message.getParams(); 4205691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang // Note that we don't support parameterized keycode now. 4215691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang // TODO: translate parameterized keycode as well. 4225691b2f2297b29dc83a7f83f77da517035b11cceJungshik Jang final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0]); 4233e1564ee397ef833cba351153029317786f3d6bbTerry Heo int keyRepeatCount = 0; 4243e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4253e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (keycode == mLastKeycode) { 4263e1564ee397ef833cba351153029317786f3d6bbTerry Heo keyRepeatCount = mLastKeyRepeatCount + 1; 4273e1564ee397ef833cba351153029317786f3d6bbTerry Heo } else { 4283e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(downTime, KeyEvent.ACTION_UP, mLastKeycode, 0); 4293e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4303e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4313e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeycode = keycode; 4323e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeyRepeatCount = keyRepeatCount; 4333e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4343e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (keycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4353e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(downTime, KeyEvent.ACTION_DOWN, keycode, keyRepeatCount); 4363e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_USER_CONTROL_RELEASE_TIMEOUT), 4373e1564ee397ef833cba351153029317786f3d6bbTerry Heo FOLLOWER_SAFETY_TIMEOUT); 4383e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 4393e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4403e1564ee397ef833cba351153029317786f3d6bbTerry Heo return false; 4413e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4423e1564ee397ef833cba351153029317786f3d6bbTerry Heo 4433e1564ee397ef833cba351153029317786f3d6bbTerry Heo @ServiceThreadOnly 4443e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected boolean handleUserControlReleased() { 4453e1564ee397ef833cba351153029317786f3d6bbTerry Heo assertRunOnServiceThread(); 4463e1564ee397ef833cba351153029317786f3d6bbTerry Heo mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT); 4473e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeyRepeatCount = 0; 4483e1564ee397ef833cba351153029317786f3d6bbTerry Heo if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { 4493e1564ee397ef833cba351153029317786f3d6bbTerry Heo final long upTime = SystemClock.uptimeMillis(); 4503e1564ee397ef833cba351153029317786f3d6bbTerry Heo injectKeyEvent(upTime, KeyEvent.ACTION_UP, mLastKeycode, 0); 4513e1564ee397ef833cba351153029317786f3d6bbTerry Heo mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE; 4523e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 4533e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 45438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 45538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 45638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 4573e1564ee397ef833cba351153029317786f3d6bbTerry Heo static void injectKeyEvent(long time, int action, int keycode, int repeat) { 4583e1564ee397ef833cba351153029317786f3d6bbTerry Heo KeyEvent keyEvent = KeyEvent.obtain(time, time, action, keycode, 4593e1564ee397ef833cba351153029317786f3d6bbTerry Heo repeat, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 4603e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputDevice.SOURCE_HDMI, null); 4613e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputManager.getInstance().injectInputEvent(keyEvent, 4623e1564ee397ef833cba351153029317786f3d6bbTerry Heo InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 4633e1564ee397ef833cba351153029317786f3d6bbTerry Heo keyEvent.recycle(); 4643e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 4653e1564ee397ef833cba351153029317786f3d6bbTerry Heo 46625c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) { 46738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo byte[] params = message.getParams(); 468c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED 469210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER 470210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_ON_FUNCTION 471210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); 47238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 47338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 47425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo static boolean isPowerOffOrToggleCommand(HdmiCecMessage message) { 47538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo byte[] params = message.getParams(); 476c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED 477210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang && (params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER 478210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_OFF_FUNCTION 479210d73df0b77b4c8be67ecc92afb238dc8c7ccfaJungshik Jang || params[0] == HdmiCecKeycode.CEC_KEYCODE_POWER_TOGGLE_FUNCTION); 48038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 48138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 48238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleTextViewOn(HdmiCecMessage message) { 48338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 48438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 48538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 48638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleImageViewOn(HdmiCecMessage message) { 48738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 48838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 48938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 49038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleSetStreamPath(HdmiCecMessage message) { 49138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return false; 49238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 49338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 49438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected boolean handleGiveDevicePowerStatus(HdmiCecMessage message) { 49538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPowerStatus( 49638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo mAddress, message.getSource(), mService.getPowerStatus())); 49738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return true; 49838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 49938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 5003e1564ee397ef833cba351153029317786f3d6bbTerry Heo protected boolean handleGiveDeviceMenuStatus(HdmiCecMessage message) { 5013e1564ee397ef833cba351153029317786f3d6bbTerry Heo // Always report menu active to receive Remote Control. 5023e1564ee397ef833cba351153029317786f3d6bbTerry Heo mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus( 5033e1564ee397ef833cba351153029317786f3d6bbTerry Heo mAddress, message.getSource(), Constants.MENU_STATE_ACTIVATED)); 5043e1564ee397ef833cba351153029317786f3d6bbTerry Heo return true; 5053e1564ee397ef833cba351153029317786f3d6bbTerry Heo } 5063e1564ee397ef833cba351153029317786f3d6bbTerry Heo 507119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim protected boolean handleVendorCommand(HdmiCecMessage message) { 508119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), 509119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim message.getParams(), false); 510119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return true; 511119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 512119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 513119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim protected boolean handleVendorCommandWithId(HdmiCecMessage message) { 514119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim byte[] params = message.getParams(); 515119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim int vendorId = HdmiUtils.threeBytesToInt(params); 516119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim if (vendorId == mService.getVendorId()) { 517119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params, true); 518119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else if (message.getDestination() != Constants.ADDR_BROADCAST && 519119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim message.getSource() != Constants.ADDR_UNREGISTERED) { 520119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.v(TAG, "Wrong direct vendor command. Replying with <Feature Abort>"); 5216aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mService.maySendFeatureAbortCommand(message, Constants.ABORT_UNRECOGNIZED_OPCODE); 522119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } else { 523119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim Slog.v(TAG, "Wrong broadcast vendor command. Ignoring"); 524119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 525119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim return true; 526119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim } 527119160a68195bcb2f5bdf4a269807e01228eca97Jinsuk Kim 5288f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang protected boolean handleSetOsdName(HdmiCecMessage message) { 5298f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang // The default behavior of <Set Osd Name> is doing nothing. 5308f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang return true; 5318f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang } 5328f2ed357a23fac4a55da43d20138b438b4ac79a7Jungshik Jang 533b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang protected boolean handleRecordTvScreen(HdmiCecMessage message) { 53425c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo // The default behavior of <Record TV Screen> is replying <Feature Abort> with 53525c20298ad04e0e591e0cfdc0bb9d01a985433abYuncheol Heo // "Cannot provide source". 5366aae6528a6672497b1d1dffb5c083093d5c46dc8Yuncheol Heo mService.maySendFeatureAbortCommand(message, Constants.ABORT_CANNOT_PROVIDE_SOURCE); 537b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang return true; 538b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang } 539b6591b8e5399099dc6b7693e0fc719b613aba89cJungshik Jang 540e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang protected boolean handleTimerClearedStatus(HdmiCecMessage message) { 541e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang return false; 542e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang } 543e5a9337ebe738633cf7b66141cdf76efcdc5754cJungshik Jang 54438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo @ServiceThreadOnly 545fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo final void handleAddressAllocated(int logicalAddress, int reason) { 54679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5473ee65720e91c7f92ad5a034d7052122a606aa8d5Jungshik Jang mAddress = mPreferredAddress = logicalAddress; 548fc44e4e03c5f6486efb7457965dcf7eaf36bc971Yuncheol Heo onAddressAllocated(logicalAddress, reason); 549af2acf0447aff34450cde2bcfb35dff9cf631729Jinsuk Kim setPreferredAddress(logicalAddress); 5501a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 5511a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 552a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 55361f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang HdmiDeviceInfo getDeviceInfo() { 55479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5551a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang return mDeviceInfo; 5561a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 5571a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 558a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 55961f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void setDeviceInfo(HdmiDeviceInfo info) { 56079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5611a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang mDeviceInfo = info; 5621a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang } 5631a4485dcd25ed036fb8de1a271b37121d8135f4eJungshik Jang 5642918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Returns true if the logical address is same as the argument. 565a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5662918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim boolean isAddressOf(int addr) { 56779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 5682918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim return addr == mAddress; 5692918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 5702918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 5712918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim // Resets the logical address to unregistered(15), meaning the logical device is invalid. 572a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 5732918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim void clearAddress() { 57479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 575c0c20d0522d7756d80f011e7a54bf3b51c78df41Jinsuk Kim mAddress = Constants.ADDR_UNREGISTERED; 5762918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim } 5772918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim 578a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 579b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang void addAndStartAction(final HdmiCecFeatureAction action) { 58079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 58138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo if (mService.isPowerStandbyOrTransient()) { 58238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo Slog.w(TAG, "Skip the action during Standby: " + action); 58338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo return; 58438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 58579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mActions.add(action); 58679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang action.start(); 58779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 58879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 58979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // See if we have an action of a given type in progress. 590a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 591b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> boolean hasAction(final Class<T> clazz) { 59279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 593b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang for (HdmiCecFeatureAction action : mActions) { 59479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action.getClass().equals(clazz)) { 59579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return true; 59679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 59779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 59879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return false; 59979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 60079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 60179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Returns all actions matched with given class type. 602a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 603b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> List<T> getActions(final Class<T> clazz) { 60479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 60543c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim List<T> actions = Collections.<T>emptyList(); 606b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang for (HdmiCecFeatureAction action : mActions) { 60779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action.getClass().equals(clazz)) { 60843c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim if (actions.isEmpty()) { 60943c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim actions = new ArrayList<T>(); 61043c23e273e1b78caf26899eca5a4f51df9d52400Jinsuk Kim } 61179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang actions.add((T) action); 61279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 61379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 61479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return actions; 61579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 61679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 61779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 618b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * Remove the given {@link HdmiCecFeatureAction} object from the action queue. 61979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 620b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang * @param action {@link HdmiCecFeatureAction} to remove 62179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 622a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 623b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang void removeAction(final HdmiCecFeatureAction action) { 62479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 625c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 62679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang mActions.remove(action); 62738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 62879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 62979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 63079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Remove all actions matched with the given Class type. 631a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 632b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> void removeAction(final Class<T> clazz) { 633a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 63479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang removeActionExcept(clazz, null); 63579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 63679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 63779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang // Remove all actions matched with the given Class type besides |exception|. 638a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 639b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang <T extends HdmiCecFeatureAction> void removeActionExcept(final Class<T> clazz, 640b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang final HdmiCecFeatureAction exception) { 64179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 642b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang Iterator<HdmiCecFeatureAction> iter = mActions.iterator(); 64379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang while (iter.hasNext()) { 644b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang HdmiCecFeatureAction action = iter.next(); 64579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (action != exception && action.getClass().equals(clazz)) { 646c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 647c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo iter.remove(); 64879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 64979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 65038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo checkIfPendingActionsCleared(); 65179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 65279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 65338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo protected void checkIfPendingActionsCleared() { 6544fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang if (mActions.isEmpty() && mPendingActionClearedCallback != null) { 65526ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo PendingActionClearedCallback callback = mPendingActionClearedCallback; 65626ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo // To prevent from calling the callback again during handling the callback itself. 65726ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo mPendingActionClearedCallback = null; 65826ba7fddcaeb052710ca8672889830dabcbfd3acYuncheol Heo callback.onCleared(this); 65938db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 66038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo } 6614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 66279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang protected void assertRunOnServiceThread() { 66379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang if (Looper.myLooper() != mService.getServiceLooper()) { 66479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang throw new IllegalStateException("Should run on service thread."); 66579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 66679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 66779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 66879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 66979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * Called when a hot-plug event issued. 67079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * 67179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param portId id of port where a hot-plug event happened 67279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang * @param connected whether to connected or not on the event 67379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 67479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang void onHotplug(int portId, boolean connected) { 67579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 67679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 67779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final HdmiControlService getService() { 67879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService; 67979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 68079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 681a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 68279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang final boolean isConnectedToArcPort(int path) { 683a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang assertRunOnServiceThread(); 68479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.isConnectedToArcPort(path); 68579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 68679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 68772b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim ActiveSource getActiveSource() { 68879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 68979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mActiveSource; 69079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 69179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 69279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 69372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void setActiveSource(ActiveSource newActive) { 69472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(newActive.logicalAddress, newActive.physicalAddress); 69572b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 69672b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 69761f4fbd2e8436a1ecd478c2a1f516d064a24d43bJungshik Jang void setActiveSource(HdmiDeviceInfo info) { 69872b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim setActiveSource(info.getLogicalAddress(), info.getPhysicalAddress()); 69972b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim } 70072b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim 70172b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim void setActiveSource(int logicalAddress, int physicalAddress) { 7028333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 70372b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mActiveSource.logicalAddress = logicalAddress; 70472b7d738d5b9254594726304cdb1777b54d95631Jinsuk Kim mActiveSource.physicalAddress = physicalAddress; 7058333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 706e9f6ed3b11fb8ebae5e73db1e4736b86cae272d9Jinsuk Kim mService.setLastInputForMhl(Constants.INVALID_PORT_ID); 7078333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 7088333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 70979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang int getActivePath() { 71079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 71179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mActiveRoutingPath; 71279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 71379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 71479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 7158333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim void setActivePath(int path) { 7168333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim synchronized (mLock) { 7178333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim mActiveRoutingPath = path; 7188333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 719867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang mService.setActivePortId(pathToPortId(path)); 7208333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim } 7218333571bd5e0a08773a1679964f8d96227af3356Jinsuk Kim 72279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang /** 723a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Returns the ID of the active HDMI port. The active port is the one that has the active 724a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * routing path connected to it directly or indirectly under the device hierarchy. 72579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang */ 726a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim int getActivePortId() { 72779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang synchronized (mLock) { 72879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.pathToPortId(mActiveRoutingPath); 72979c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 73179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 732a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim /** 733a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * Update the active port. 734a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * 735a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim * @param portId the new active port id 736a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim */ 737a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim void setActivePortId(int portId) { 738867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang // We update active routing path instead, since we get the active port id from 739867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang // the active routing path. 740867b4e0c55b4b1e432a3585fc945a999f066ef81Jungshik Jang setActivePath(mService.portIdToPath(portId)); 741a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim } 742a062a9339add79a84862a34e363e3e454a6ec435Jinsuk Kim 743a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 74479c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang HdmiCecMessageCache getCecMessageCache() { 74579c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 74679c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mCecMessageCache; 74779c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 74879c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang 749a5b7414970c85217e88015e78ecbc5ba093dead3Jungshik Jang @ServiceThreadOnly 75079c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang int pathToPortId(int newPath) { 75179c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang assertRunOnServiceThread(); 75279c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang return mService.pathToPortId(newPath); 75379c58a4b97f27ede6a1b680d2fece9c2a0edf7b7Jungshik Jang } 75438db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 75538db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 7564fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * Called when the system goes to standby mode. 75738db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * 75838db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * @param initiatedByCec true if this power sequence is initiated 759b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * by the reception the CEC messages like <Standby> 76038db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 7614fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang protected void onStandby(boolean initiatedByCec) {} 76238db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo 76338db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo /** 7644fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * Disable device. {@code callback} is used to get notified when all pending 7654fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * actions are completed or timeout is issued. 76638db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo * 7674fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * @param initiatedByCec true if this sequence is initiated 768b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * by the reception the CEC messages like <Standby> 769b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * @param origialCallback callback interface to get notified when all pending actions are 770b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang * cleared 77138db629d897e9d7c8e31ce0a7e985981e3e12996Yuncheol Heo */ 772b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang protected void disableDevice(boolean initiatedByCec, 773b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang final PendingActionClearedCallback origialCallback) { 774b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang mPendingActionClearedCallback = new PendingActionClearedCallback() { 775b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang @Override 776b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang public void onCleared(HdmiCecLocalDevice device) { 777b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang mHandler.removeMessages(MSG_DISABLE_DEVICE_TIMEOUT); 778b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang origialCallback.onCleared(device); 779b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang } 780b3e114af17c91a409e766e111e472f600f7b866cJungshik Jang }; 7814fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_DISABLE_DEVICE_TIMEOUT), 7824fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang DEVICE_CLEANUP_TIMEOUT); 7834fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 7844fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 7854fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang @ServiceThreadOnly 7864fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang private void handleDisableDeviceTimeout() { 7874fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang assertRunOnServiceThread(); 7884fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang 7894fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // If all actions are not cleared in DEVICE_CLEANUP_TIMEOUT, enforce to finish them. 7904fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang // onCleard will be called at the last action's finish method. 791b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang Iterator<HdmiCecFeatureAction> iter = mActions.iterator(); 7924fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang while (iter.hasNext()) { 793b509c2ecd99619248b7a07fb0fa978bb27f25cc3Jungshik Jang HdmiCecFeatureAction action = iter.next(); 794c516d65fd96cdc39f9935ddb80d26ee6499a77bfYuncheol Heo action.finish(false); 7954fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang iter.remove(); 7964fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 7974fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang } 798c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim 799c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim /** 800c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * Send a key event to other device. 801c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * 8024fc1d105fc279bf7df6c876e160672866bdad8e7Jungshik Jang * @param keyCode key code defined in {@link android.view.KeyEvent} 803c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim * @param isPressed {@code true} for key down event 804c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim */ 805c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim protected void sendKeyEvent(int keyCode, boolean isPressed) { 806c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim Slog.w(TAG, "sendKeyEvent not implemented"); 807c068bb5a0468bf605b0398e6f0ea5721917de4eeJinsuk Kim } 808959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo 809959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo /** 810959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo * Dump internal status of HdmiCecLocalDevice object. 811959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo */ 812959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo protected void dump(final IndentingPrintWriter pw) { 813959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mDeviceType: " + mDeviceType); 814959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mAddress: " + mAddress); 815959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mPreferredAddress: " + mPreferredAddress); 816959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mDeviceInfo: " + mDeviceInfo); 817959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println("mActiveSource: " + mActiveSource); 818959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo pw.println(String.format("mActiveRoutingPath: 0x%04x", mActiveRoutingPath)); 819959d2db12c7c6a06465af1251bc4cece580a72a3Terry Heo } 8202918e9e133de8066ab497a5f8dac1c310c792767Jinsuk Kim} 821