TvInput Cec key事件传递流程
一、TV应用MainActivity
1.dispatchInputEvent
这里会特殊处理back键,只有Home键才会退出TV应用,back键会传递给cec连接的device处理。如果按键不在黑名单里面,会传递给应用处理。比如音量键就不会传递出去。
public boolean dispatchKeyEvent(KeyEvent event) {if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "dispatchKeyEvent(" + event + ")");// If an activity is closed on a back key down event, back key down events with none zero// repeat count or a back key up event can be happened without the first back key down// event which should be ignored in this activity.if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {mBackKeyPressed = true;}if (!mBackKeyPressed) {return true;}if (event.getAction() == KeyEvent.ACTION_UP) {mBackKeyPressed = false;}}.......if (BLACKLIST_KEYCODE_TO_TIS.contains(event.getKeyCode())|| KeyEvent.isGamepadButton(event.getKeyCode())) {// If the event is in blacklisted or gamepad key, do not pass it to session.// Gamepad keys are blacklisted to support TV UIs and here's the detail.// If there's a TIS granted RECEIVE_INPUT_EVENT, TIF sends key events to TIS// and return immediately saying that the event is handled.// In this case, fallback key will be injected but with FLAG_CANCELED// while gamepads support DPAD_CENTER and BACK by fallback.// Since we don't expect that TIS want to handle gamepad buttons now,// blacklist gamepad buttons and wait for next fallback keys.// TODO: Need to consider other fallback keys (e.g. ESCAPE)if (SystemProperties.USE_KEY.getValue() || TvSingletons.getSingletons(this).getSystemControlManager().getPropertyBoolean("tv.platform.need_key", false)) {if (event.getAction() == KeyEvent.ACTION_UP) {if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {// It takes long time for TV app to finish, so stop TV first.stopAll(false);super.onBackPressed();return true;}onKeyUp(event.getKeyCode(), event);} else if (event.getAction() == KeyEvent.ACTION_DOWN) {onKeyDown(event.getKeyCode(), event);}return true;} else {return super.dispatchKeyEvent(event);}}return dispatchKeyEventToSession(event) || super.dispatchKeyEvent(event);}
2.dispatchKeyEventToSession
这里主要是把KeyEvent交给TvView处理,因为TvView里面保存着对应的Session。
private boolean dispatchKeyEventToSession(final KeyEvent event) {if (SystemProperties.LOG_KEYEVENT.getValue()) {Log.d(TAG, "dispatchKeyEventToSession(" + event + ")");}.....boolean handled = false;if (mTvView != null) {handled = mTvView.dispatchKeyEvent(event);}....return handled;}
3.TunableTvView dispatchKeyEvent
只有在正常tune建立session之后才会传递key事件。
@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {return mCanReceiveInputEvent && mTvView.dispatchKeyEvent(event);}
TvView 下面就是通过session将key event发出去了。
@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {if (super.dispatchKeyEvent(event)) {return true;}if (DEBUG) Log.d(TAG, "dispatchKeyEvent(" + event + ")");if (mSession == null) {return false;}InputEvent copiedEvent = event.copy();int ret = mSession.dispatchInputEvent(copiedEvent, copiedEvent, mFinishedInputEventCallback,mHandler);return ret != Session.DISPATCH_NOT_HANDLED;}
4.TvInputService.Session
主要是KeyEvent.dispatch,在具体的子类Session里面实现KeyEvent的onKeyDown和onKeyUp来进行处理。
/*** Takes care of dispatching incoming input events and tells whether the event was handled.*/int dispatchInputEvent(InputEvent event, InputEventReceiver receiver) {if (DEBUG) Log.d(TAG, "dispatchInputEvent(" + event + ")");boolean isNavigationKey = false;boolean skipDispatchToOverlayView = false;if (event instanceof KeyEvent) {KeyEvent keyEvent = (KeyEvent) event;if (keyEvent.dispatch(this, mDispatcherState, this)) {return TvInputManager.Session.DISPATCH_HANDLED;}isNavigationKey = isNavigationKey(keyEvent.getKeyCode());// When media keys and KEYCODE_MEDIA_AUDIO_TRACK are dispatched to ViewRootImpl,// ViewRootImpl always consumes the keys. In this case, the application loses// a chance to handle media keys. Therefore, media keys are not dispatched to// ViewRootImpl.skipDispatchToOverlayView = KeyEvent.isMediaKey(keyEvent.getKeyCode())|| keyEvent.getKeyCode() == KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK;} .........}
5.TvInputBaseSession
具体的code不能贴,但后续主要是通过当前的TvClient设备进行KeyEvent的传递。
mTvClient.sendKeyEvent
6.HdmiClient sendKeyEvent
public void sendKeyEvent(int keyCode, boolean isPressed) {try {mService.sendKeyEvent(getDeviceType(), keyCode, isPressed);} catch (RemoteException e) {Log.e(TAG, "sendKeyEvent threw exception ", e);}}
7.HdmiControlService sendKeyEvent
要通过当前的HdmiCecLocalDevice来发送
@Overridepublic void sendKeyEvent(final int deviceType, final int keyCode, final boolean isPressed) {enforceAccessPermission();runOnServiceThreadAtFrontOfQueue(new Runnable() {@Overridepublic void run() {Slog.d(TAG, "sendKeyEvent deviceType " + deviceType + " keyCode " + keyCode);....if (mCecController != null) {HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(deviceType);if (localDevice == null) {Slog.w(TAG, "Local device not available");return;}localDevice.sendKeyEvent(keyCode, isPressed);}}});}
8.HdmiCecLocalDevice sendKeyEvent
发起SendKeyAction
protected void sendKeyEvent(int keyCode, boolean isPressed) {assertRunOnServiceThread();HdmiLogger.debug("sendKeyEvent keyCode: " + keyCode);if (!HdmiCecKeycode.isSupportedKeycode(keyCode)) {Slog.w(TAG, "Unsupported key: " + keyCode);return;}List<SendKeyAction> action = getActions(SendKeyAction.class);int logicalAddress = findKeyReceiverAddress();if (logicalAddress == Constants.ADDR_INVALID || logicalAddress == mAddress) {// Don't send key event to invalid device or itself.Slog.w(TAG, "Discard key event: " + keyCode + ", pressed:" + isPressed+ ", receiverAddr=" + logicalAddress);} else if (!action.isEmpty()) {action.get(0).processKeyEvent(keyCode, isPressed);} else if (isPressed) {addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode));}}
9.SendKeyAction
这里会将Android的KeyEvent转化成Cec的keyEvent,opcode是MESSAGE_USER_CONTROL_PRESSED即0x44.
比如04 44 02,就表示发送给playback一个向下键。
/*** Called when a key event should be handled for the action.** @param keycode key code of {@link KeyEvent} object* @param isPressed true if the key event is of {@link KeyEvent#ACTION_DOWN}*/void processKeyEvent(int keycode, boolean isPressed) {if (mState != STATE_CHECKING_LONGPRESS && mState != STATE_PROCESSING_KEYCODE) {Slog.w(TAG, "Not in a valid state");return;}if (isPressed) {// A new key press event that comes in with a key code different from the last// one becomes a new key code to be used for press-and-hold operation.if (keycode != mLastKeycode) {sendKeyDown(keycode);mLastSendKeyTime = getCurrentTime();if (!HdmiCecKeycode.isRepeatableKey(keycode)) {sendKeyUp();finish();return;}} else {// Press-and-hold key transmission takes place if Android key inputs are// repeatedly coming in and more than IRT_MS has passed since the last// press-and-hold key transmission.if (getCurrentTime() - mLastSendKeyTime >= IRT_MS) {sendKeyDown(keycode);mLastSendKeyTime = getCurrentTime();}}mActionTimer.clearTimerMessage();addTimer(mState, AWAIT_RELEASE_KEY_MS);mLastKeycode = keycode;} else {// Key release event indicates that the action shall be finished. Send UCR// command and terminate the action. Other release events are ignored.if (keycode == mLastKeycode) {sendKeyUp();finish();}}}private void sendKeyDown(int keycode) {byte[] cecKeycodeAndParams = HdmiCecKeycode.androidKeyToCecKey(keycode);if (cecKeycodeAndParams == null) {return;}sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(),mTargetAddress, cecKeycodeAndParams));}
HdmiCecKeyCode
// Hdmi CEC keycodespublic static final int CEC_KEYCODE_SELECT = 0x00;public static final int CEC_KEYCODE_UP = 0x01;public static final int CEC_KEYCODE_DOWN = 0x02;public static final int CEC_KEYCODE_LEFT = 0x03;public static final int CEC_KEYCODE_RIGHT = 0x04;public static final int CEC_KEYCODE_RIGHT_UP = 0x05;public static final int CEC_KEYCODE_RIGHT_DOWN = 0x06;public static final int CEC_KEYCODE_LEFT_UP = 0x07;public static final int CEC_KEYCODE_LEFT_DOWN = 0x08;public static final int CEC_KEYCODE_ROOT_MENU = 0x09;public static final int CEC_KEYCODE_SETUP_MENU = 0x0A;public static final int CEC_KEYCODE_CONTENTS_MENU = 0x0B;public static final int CEC_KEYCODE_FAVORITE_MENU = 0x0C;public static final int CEC_KEYCODE_EXIT = 0x0D;// RESERVED = 0x0E - 0x0Fpublic static final int CEC_KEYCODE_MEDIA_TOP_MENU = 0x10;public static final int CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU = 0x11;// RESERVED = 0x12 – 0x1Cpublic static final int CEC_KEYCODE_NUMBER_ENTRY_MODE = 0x1D;public static final int CEC_KEYCODE_NUMBER_11 = 0x1E;public static final int CEC_KEYCODE_NUMBER_12 = 0x1F;public static final int CEC_KEYCODE_NUMBER_0_OR_NUMBER_10 = 0x20;public static final int CEC_KEYCODE_NUMBERS_1 = 0x21;public static final int CEC_KEYCODE_NUMBERS_2 = 0x22;public static final int CEC_KEYCODE_NUMBERS_3 = 0x23;public static final int CEC_KEYCODE_NUMBERS_4 = 0x24;public static final int CEC_KEYCODE_NUMBERS_5 = 0x25;public static final int CEC_KEYCODE_NUMBERS_6 = 0x26;public static final int CEC_KEYCODE_NUMBERS_7 = 0x27;public static final int CEC_KEYCODE_NUMBERS_8 = 0x28;public static final int CEC_KEYCODE_NUMBERS_9 = 0x29;public static final int CEC_KEYCODE_DOT = 0x2A;public static final int CEC_KEYCODE_ENTER = 0x2B;public static final int CEC_KEYCODE_CLEAR = 0x2C;// RESERVED = 0x2D - 0x2Epublic static final int CEC_KEYCODE_NEXT_FAVORITE = 0x2F;public static final int CEC_KEYCODE_CHANNEL_UP = 0x30;public static final int CEC_KEYCODE_CHANNEL_DOWN = 0x31;public static final int CEC_KEYCODE_PREVIOUS_CHANNEL = 0x32;public static final int CEC_KEYCODE_SOUND_SELECT = 0x33;public static final int CEC_KEYCODE_INPUT_SELECT = 0x34;public static final int CEC_KEYCODE_DISPLAY_INFORMATION = 0x35;public static final int CEC_KEYCODE_HELP = 0x36;public static final int CEC_KEYCODE_PAGE_UP = 0x37;public static final int CEC_KEYCODE_PAGE_DOWN = 0x38;// RESERVED = 0x39 - 0x3Fpublic static final int CEC_KEYCODE_POWER = 0x40;public static final int CEC_KEYCODE_VOLUME_UP = 0x41;public static final int CEC_KEYCODE_VOLUME_DOWN = 0x42;public static final int CEC_KEYCODE_MUTE = 0x43;public static final int CEC_KEYCODE_PLAY = 0x44;public static final int CEC_KEYCODE_STOP = 0x45;public static final int CEC_KEYCODE_PAUSE = 0x46;public static final int CEC_KEYCODE_RECORD = 0x47;public static final int CEC_KEYCODE_REWIND = 0x48;public static final int CEC_KEYCODE_FAST_FORWARD = 0x49;public static final int CEC_KEYCODE_EJECT = 0x4A;public static final int CEC_KEYCODE_FORWARD = 0x4B;public static final int CEC_KEYCODE_BACKWARD = 0x4C;public static final int CEC_KEYCODE_STOP_RECORD = 0x4D;public static final int CEC_KEYCODE_PAUSE_RECORD = 0x4E;public static final int CEC_KEYCODE_RESERVED = 0x4F;public static final int CEC_KEYCODE_ANGLE = 0x50;public static final int CEC_KEYCODE_SUB_PICTURE = 0x51;public static final int CEC_KEYCODE_VIDEO_ON_DEMAND = 0x52;public static final int CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE = 0x53;public static final int CEC_KEYCODE_TIMER_PROGRAMMING = 0x54;public static final int CEC_KEYCODE_INITIAL_CONFIGURATION = 0x55;public static final int CEC_KEYCODE_SELECT_BROADCAST_TYPE = 0x56;public static final int CEC_KEYCODE_SELECT_SOUND_PRESENTATION = 0x57;// RESERVED = 0x58-0x5Fpublic static final int CEC_KEYCODE_PLAY_FUNCTION = 0x60;public static final int CEC_KEYCODE_PAUSE_PLAY_FUNCTION = 0x61;public static final int CEC_KEYCODE_RECORD_FUNCTION = 0x62;public static final int CEC_KEYCODE_PAUSE_RECORD_FUNCTION = 0x63;public static final int CEC_KEYCODE_STOP_FUNCTION = 0x64;public static final int CEC_KEYCODE_MUTE_FUNCTION = 0x65;public static final int CEC_KEYCODE_RESTORE_VOLUME_FUNCTION = 0x66;public static final int CEC_KEYCODE_TUNE_FUNCTION = 0x67;public static final int CEC_KEYCODE_SELECT_MEDIA_FUNCTION = 0x68;public static final int CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION = 0x69;public static final int CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION = 0x6A;public static final int CEC_KEYCODE_POWER_TOGGLE_FUNCTION = 0x6B;public static final int CEC_KEYCODE_POWER_OFF_FUNCTION = 0x6C;public static final int CEC_KEYCODE_POWER_ON_FUNCTION = 0x6D;// RESERVED = 0x6E-0x70public static final int CEC_KEYCODE_F1_BLUE = 0x71;public static final int CEC_KEYCODE_F2_RED = 0x72;public static final int CEC_KEYCODE_F3_GREEN = 0x73;public static final int CEC_KEYCODE_F4_YELLOW = 0x74;public static final int CEC_KEYCODE_F5 = 0x75;public static final int CEC_KEYCODE_DATA = 0x76;
后面就是经过HDMI CEC hal service将cec command发给内核驱动去处理,和其他的cec command的流程没有区别了。
TvInput Cec key事件传递流程相关推荐
- Android webkit 事件传递流程
前言:基于android webview 上定制自己使用的可移植浏览器apk,遇到好多按键处理的问题.所以索***了一下keyevent 事件的传递流程. frameworks 层 keyevent ...
- UGUI事件传递流程解析
很多Unity3D项目都使用了UGUI,但并不是所有人都研究过它的内部结构.针对事件的传递过程,会问住大多数未深入思考过的开发者.由于UGUI是开源的,我们可以通过查看源码来熟悉它的原理,它的地址在可 ...
- android touch事件坐标原点,图解Android:Touch事件传递机制
前言 Android事件管理机制是一名专业Android研发工程师必须要了解的核心知识之一,深入了解一下该机制无论对我们日常开发还是找工作,乃至于对我们的架构思想都有很大的帮助.Android中我们用 ...
- Android自定义View2--触摸事件传递机制
转载文章 :https://juejin.im/post/6844904041487532045#heading-6 https://juejin.im/post/684490389410388378 ...
- Android 事件传递机制总结
Android 事件传递机制总结 Android View虽然不是四大组件,但是其重要程度堪比四大组件.初级工程师到中高级工程师,这些都是很重要的,因为事件分发机制面试也会经常被提及,如果我们能get ...
- Android事件传递可以这样理解
前言 关于Android中事件传递机制早已是老生常谈的话题,甭管工作多久水平咋样应该都能道出一二.依稀记得刚接触事件分发那会,一股脑的钻进网络上那几张神图,什么三大方法.职责链,最后再巴拉巴拉贴一大堆 ...
- Android面试必问之触摸事件传递机制
Android面试必问之触摸事件传递机制 一.Activity的构成 二.触摸事件的类型 三.事件传递的三个阶段 Activity对点击事件的分发过程 五.View的事件分发机制 六.点击事件分发的传 ...
- android 事件派发流程详解
Android 5.0(Lollipop)事件输入系统(Input System) 2014-12-15 23 个评论 来源:世事难料,保持低调 收藏 我要投稿 其实Androi ...
- Android Touch事件传递机制 二:单纯的(伪生命周期) 这个清楚一点
转载于:http://blog.csdn.net/yuanzeyao/article/details/38025165 在前一篇文章中,我主要讲解了Android源码中的Touch事件的传递过程,现在 ...
最新文章
- TCP/IP四层模型和OSI七层模型
- 如何通过域服务器推送安装文件,域环境推送exe程序并自动安装教程域环境推送exe程序并自动安装教程.pdf...
- mq系列传感器的程序_消息中间件(一)MQ详解及四大MQ比较
- Java数据结构 反转链表
- 编写更好的 Java 单元测试的 7 个技巧
- 如何设计高可用的微服务架构
- 在centos7中安装redis,并通过node.js操作redis
- android开机启动service
- 40+张最全Linux/C/C++思维导图,收藏!
- Win7下硬盘安装Ubuntu10.10双系统
- 推给我的广告都跟我最近看的内容有关系,怎么做到的?
- .net开发中常用的第三方组件
- gvim配置文件参考
- Jetson Nano 读取 GPS数据(TTL转 USB)
- linux fastboot 工具下载,FastBoot刷机工具
- python进阶小技巧
- eclipse安装插件速度很慢的解决方案
- 无法通过百度联盟申请的常见原因
- AutoCAD打印图纸如何使参照底图灰度显示
- matlab单层感知器画线,使用MATLAB编写单层感知器