am 68f5e8f0: am 0190fd8a: am f9ed92a3: Merge "CEC: Handle Remote Control command" into lmp-dev
* commit '68f5e8f07360b24d1088976379b2becba6d4c5d3': CEC: Handle Remote Control command
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -337,6 +337,21 @@ public class HdmiCecMessageBuilder {
|
||||
return buildCommand(src, dest, Constants.MESSAGE_REPORT_POWER_STATUS, param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build <Report Menu Status> 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 <System Audio Mode Request> command.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user