summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTerry Heo <terryheo@google.com>2014-08-18 07:37:58 +0000
committerAndroid Git Automerger <android-git-automerger@android.com>2014-08-18 07:37:58 +0000
commitb47e183ca950213318f913a87af839e362c9a302 (patch)
tree64ae278af8abd2f7969f6b1e96b1f9ac3abb22ab
parent26c2c1731c5f0714c62fbff3f4f13f9b3093cb4b (diff)
parentdbbbb8d4017fe4cc30bfd9a68ff54e73abb58f64 (diff)
downloadframeworks_base-b47e183ca950213318f913a87af839e362c9a302.zip
frameworks_base-b47e183ca950213318f913a87af839e362c9a302.tar.gz
frameworks_base-b47e183ca950213318f913a87af839e362c9a302.tar.bz2
am 0190fd8a: am f9ed92a3: Merge "CEC: Handle Remote Control command" into lmp-dev
* commit '0190fd8a6f9389f9eab0a908bcc1b78ecce5fb4b': CEC: Handle Remote Control command
-rw-r--r--services/core/java/com/android/server/hdmi/Constants.java4
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java71
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java15
3 files changed, 90 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java
index ae7472d..4b812cf 100644
--- a/services/core/java/com/android/server/hdmi/Constants.java
+++ b/services/core/java/com/android/server/hdmi/Constants.java
@@ -173,6 +173,10 @@ final class Constants {
static final int SYSTEM_AUDIO_STATUS_OFF = 0;
static final int SYSTEM_AUDIO_STATUS_ON = 1;
+ // [Menu State]
+ static final int MENU_STATE_ACTIVATED = 0;
+ static final int MENU_STATE_DEACTIVATED = 1;
+
// Bit mask used to get the routing path of the top level device.
// When &'d with the path 1.2.2.0 (0x1220), for instance, gives 1.0.0.0.
static final int ROUTING_PATH_TOP_MASK = 0xF000;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index b894fd7..4862f93 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -17,10 +17,15 @@
package com.android.server.hdmi;
import android.hardware.hdmi.HdmiDeviceInfo;
+import android.hardware.input.InputManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.SystemClock;
import android.util.Slog;
+import android.view.InputDevice;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
import com.android.internal.annotations.GuardedBy;
import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
@@ -39,15 +44,21 @@ abstract class HdmiCecLocalDevice {
private static final String TAG = "HdmiCecLocalDevice";
private static final int MSG_DISABLE_DEVICE_TIMEOUT = 1;
+ private static final int MSG_USER_CONTROL_RELEASE_TIMEOUT = 2;
// Timeout in millisecond for device clean up (5s).
// Normal actions timeout is 2s but some of them would have several sequence of timeout.
private static final int DEVICE_CLEANUP_TIMEOUT = 5000;
+ // Within the timer, a received <User Control Pressed> will start "Press and Hold" behavior.
+ // When it expires, we can assume <User Control Release> is received.
+ private static final int FOLLOWER_SAFETY_TIMEOUT = 550;
protected final HdmiControlService mService;
protected final int mDeviceType;
protected int mAddress;
protected int mPreferredAddress;
protected HdmiDeviceInfo mDeviceInfo;
+ protected int mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
+ protected int mLastKeyRepeatCount = 0;
static class ActiveSource {
int logicalAddress;
@@ -111,6 +122,9 @@ abstract class HdmiCecLocalDevice {
case MSG_DISABLE_DEVICE_TIMEOUT:
handleDisableDeviceTimeout();
break;
+ case MSG_USER_CONTROL_RELEASE_TIMEOUT:
+ handleUserControlReleased();
+ break;
}
}
};
@@ -230,10 +244,14 @@ abstract class HdmiCecLocalDevice {
return handleImageViewOn(message);
case Constants.MESSAGE_USER_CONTROL_PRESSED:
return handleUserControlPressed(message);
+ case Constants.MESSAGE_USER_CONTROL_RELEASED:
+ return handleUserControlReleased();
case Constants.MESSAGE_SET_STREAM_PATH:
return handleSetStreamPath(message);
case Constants.MESSAGE_GIVE_DEVICE_POWER_STATUS:
return handleGiveDevicePowerStatus(message);
+ case Constants.MESSAGE_MENU_REQUEST:
+ return handleGiveDeviceMenuStatus(message);
case Constants.MESSAGE_VENDOR_COMMAND:
return handleVendorCommand(message);
case Constants.MESSAGE_VENDOR_COMMAND_WITH_ID:
@@ -376,6 +394,7 @@ abstract class HdmiCecLocalDevice {
@ServiceThreadOnly
protected boolean handleUserControlPressed(HdmiCecMessage message) {
assertRunOnServiceThread();
+ mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT);
if (mService.isPowerOnOrTransient() && isPowerOffOrToggleCommand(message)) {
mService.standby();
return true;
@@ -383,9 +402,54 @@ abstract class HdmiCecLocalDevice {
mService.wakeUp();
return true;
}
+
+ final long downTime = SystemClock.uptimeMillis();
+ final byte[] params = message.getParams();
+ final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0],
+ params.length > 1 ? params[1] : HdmiCecKeycode.NO_PARAM);
+ int keyRepeatCount = 0;
+ if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ if (keycode == mLastKeycode) {
+ keyRepeatCount = mLastKeyRepeatCount + 1;
+ } else {
+ injectKeyEvent(downTime, KeyEvent.ACTION_UP, mLastKeycode, 0);
+ }
+ }
+ mLastKeycode = keycode;
+ mLastKeyRepeatCount = keyRepeatCount;
+
+ if (keycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ injectKeyEvent(downTime, KeyEvent.ACTION_DOWN, keycode, keyRepeatCount);
+ mHandler.sendMessageDelayed(Message.obtain(mHandler, MSG_USER_CONTROL_RELEASE_TIMEOUT),
+ FOLLOWER_SAFETY_TIMEOUT);
+ return true;
+ }
+ return false;
+ }
+
+ @ServiceThreadOnly
+ protected boolean handleUserControlReleased() {
+ assertRunOnServiceThread();
+ mHandler.removeMessages(MSG_USER_CONTROL_RELEASE_TIMEOUT);
+ mLastKeyRepeatCount = 0;
+ if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) {
+ final long upTime = SystemClock.uptimeMillis();
+ injectKeyEvent(upTime, KeyEvent.ACTION_UP, mLastKeycode, 0);
+ mLastKeycode = HdmiCecKeycode.UNSUPPORTED_KEYCODE;
+ return true;
+ }
return false;
}
+ static void injectKeyEvent(long time, int action, int keycode, int repeat) {
+ KeyEvent keyEvent = KeyEvent.obtain(time, time, action, keycode,
+ repeat, 0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM,
+ InputDevice.SOURCE_HDMI, null);
+ InputManager.getInstance().injectInputEvent(keyEvent,
+ InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
+ keyEvent.recycle();
+ }
+
static boolean isPowerOnOrToggleCommand(HdmiCecMessage message) {
byte[] params = message.getParams();
return message.getOpcode() == Constants.MESSAGE_USER_CONTROL_PRESSED
@@ -420,6 +484,13 @@ abstract class HdmiCecLocalDevice {
return true;
}
+ protected boolean handleGiveDeviceMenuStatus(HdmiCecMessage message) {
+ // Always report menu active to receive Remote Control.
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus(
+ mAddress, message.getSource(), Constants.MENU_STATE_ACTIVATED));
+ return true;
+ }
+
protected boolean handleVendorCommand(HdmiCecMessage message) {
mService.invokeVendorCommandListeners(mDeviceType, message.getSource(),
message.getParams(), false);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
index 0855bfa..b53cd45 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java
@@ -338,6 +338,21 @@ public class HdmiCecMessageBuilder {
}
/**
+ * Build &lt;Report Menu Status&gt; command.
+ *
+ * @param src source address of command
+ * @param dest destination address of command
+ * @param menuStatus menu status of the device
+ * @return newly created {@link HdmiCecMessage}
+ */
+ static HdmiCecMessage buildReportMenuStatus(int src, int dest, int menuStatus) {
+ byte[] param = new byte[] {
+ (byte) (menuStatus)
+ };
+ return buildCommand(src, dest, Constants.MESSAGE_MENU_STATUS, param);
+ }
+
+ /**
* Build &lt;System Audio Mode Request&gt; command.
*
* @param src source address of command