最近,对Andoid中APK做了一些修改,让其支持遥控器的支持,这把人弄得焦头烂额,好不郁闷,这里特别记录下思路,留给有需要的同志。

其实Android本身是做了对遥控器的上下左右按键的焦点移动控制,以及对Enter键的响应,现在知道的原因就是1:View的子类在派生时对其动作做了从写,导致其焦点控制失效;2:不明原因导致焦点控制失败。该文只是从功能上总结了自己在APK的IR修改中摸索出的一些方法,来达到支持IR控制的效果。

思路一:android提供了一些焦点相关的属性,在现有的框架层下通过设置View的属性来获得焦点

android:focusable:设置一个控件能否获得焦点

android:background:设置在作为背景的drawable

android:nextFocusDown:定义下一个获得焦点的控件当按下键时

android:nextFocusUp:定义下一个获得焦点的控件当按上键时

android:nextFocusLeft:定义下一个获得焦点的控件当按左键时

android:nextFocusRight:定义下一个获得焦点的控件当按右键时

:强制设置一个焦点到指定的view或它的一个子类,前提是android:focusable为true能够获得焦点

实例一:

android:id="@+id/close"

android:focusable="true"

android:nextFocusDown="@+id/url"

android:background="?android:attr/selectableItemBackground"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:contentDescription="@string/accessibility_button_closetab"

android:src="@drawable/ic_tab_close" />

实例二:

……

……

android:imeOptions="flagNoFullscreen">

实践经验:如果XML设置无效的话,尝试下在代码中XXX.requestFocus()显式设置

思路二:自己管理焦点的移动,自己进行高亮的重绘,自己进行enter键的响应,总之:一切都靠你自己

Step 1:焦点的移动,首先你就要做到IR按键的捕获与响应

单独Activity的话,下面的两组函数都能够捕获按键消息

public boolean dispatchKeyEvent (KeyEvent event)

public boolean onKeyDown (int keyCode, KeyEvent event)

public boolean onKeyUp(int keyCode, KeyEvent event)

public boolean dispatchKeyEventPreIme (KeyEvent event)

public boolean onKeyPreIme (int keyCode, KeyEvent event)

一般来说重写onKeyDown和onKeyUp就可以了,但需要在输入法之前做一些动作,便需要重写onKeyPreIme,但是在某些时候在事件分发中会被分发到其他的view的事件处理,导致不会调用到该Activity的onKeyDown和onKeyUp,这个时候就需要在分发函数dispatchKeyEvent和dispatchKeyEventPreIme做一些动作了;要显式调用某个view的事件处理函数或是自定义的事件处理函数,也可以在以上的几个函数中进行直接调用,相当于绕开系统自己来进行一些事件的分发(只是解决方案,做法并不规范);以上这一系列函数的返回值是boolean型,如果你已经处理了一些消息,记得返回true来通知系统已经做了处理,交由系统处理的消息直接父类super的同名函数进行处理;有些按键系统对其所做的关键响应有的是在onKeyUp或者onKeyDown中,因此在你拦截的时候需在恰当的函数里进行拦截。

实例一:

@Override

public boolean onKeyUp(int keyCode, KeyEvent event){

ActivityState topState = getStateManager().getTopState();

if(topState == null){

return super.onKeyUp(keyCode, event);

}

/*显式调用ActivityState的onKeyUp事件处理,这个onKeyUp可以是重写View的消息处理,不是View

的话也可以自定义这个函数来进行事件处理,当然在这里你可以直接switch keyCode来进行当前Activity

事件处理*/

if(topState.onKeyUp(keyCode, event)){

return true;

}

else{

return super.onKeyUp(keyCode, event);

}

}

@Override

public boolean onTouchEvent(MotionEvent ev){

ActivityState topState = getStateManager().getTopState();

if(topState == null){

return super.onTouchEvent(ev);

}

if(topState.onTouchEvent(ev)){

return true;

}

else{

return super.onTouchEvent(ev);

}

}

/*

在按键事件的分发时期进行拦截,做一些自己想做的处理

*/

@Override

public boolean dispatchKeyEvent (KeyEvent event){

int keyCode = event.getKeyCode();

ActivityState topState = getStateManager().getTopState();

if(topState == null){

return super.dispatchKeyEvent(event);

}

//sometimes even the actionbar is hide,but the input focus is on the actionbar,so when the focus is on

//the slot,we should intercept the enterkeyevent action from the system

if(event.getAction() == KeyEvent.ACTION_UP){

if(topState.getFocusOnSlotView()

&& keyCode == KeyEvent.KEYCODE_ENTER){

return topState.onKeyUp(keyCode, event);

}

}

return super.dispatchKeyEvent(event);

}

@Override

public boolean dispatchTouchEvent (MotionEvent ev){

ActivityState topState = getStateManager().getTopState();

if(topState == null){

return super.dispatchTouchEvent(ev);

}

if(ev.getAction() == MotionEvent.ACTION_DOWN){

//if the user control the gallery by mouse,you should clear the focus rect

topState.setFocusOnSlotView(false);

}

return super.dispatchTouchEvent(ev);

}

实例二:

@Override

public boolean onKeyDown(int keyCode, KeyEvent event) {

final int uniChar = event.getUnicodeChar();

final boolean handled = super.onKeyDown(keyCode, event);

final boolean isKeyNotWhitespace = uniChar > 0 && !Character.isWhitespace(uniChar);

if (!handled && acceptFilter() && isKeyNotWhitespace) {

boolean gotKey = TextKeyListener.getInstance().onKeyDown(mWorkspace, mDefaultKeySsb,

keyCode, event);

if (gotKey && mDefaultKeySsb != null && mDefaultKeySsb.length() > 0) {

return onSearchRequested();

}

}

// Eat the long press event so the keyboard doesn't come up.

if (keyCode == KeyEvent.KEYCODE_MENU && event.isLongPress()) {

return true;

}

return handled;

}

假如要控制的是一个View的话,你的这个View是顶层并能获得焦点,对你有帮助的函数如下

public void setOnKeyListener (View.OnKeyListener l)

public boolean dispatchKeyEvent (KeyEvent event)

public boolean dispatchKeyEventPreIme (KeyEvent event)

第一组的作用在于你定义一个View.OnKeyListener,并重写其onClick函数,自己来处理按键消息,并将此listener注册进该view中;第二组的作用当然是使你在事件分发或输入法之前的时候进行自定义的一些操作

实例一:

OnKeyListener mCheckboxKeyListenner = new OnKeyListener(){

public boolean onKey(View v, int keyCode, KeyEvent event){

return onKeyDone(v, keyCode, event);

}

};

public boolean onKeyDone(View v, int keyCode, KeyEvent event) {

CollectCurrentSelected();

if(event.getAction() == KeyEvent.ACTION_UP){

return moveIndexOnKeyUp(keyCode);

}

if(event.getAction() == KeyEvent.ACTION_DOWN){

return moveIndexOnKeyDown(keyCode);

}

return false;

}

private boolean moveIndexOnKeyUp(int keyCode){

if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){

if(mResponseIndex == INDEX_SETTINGBTN){

return true;

}

}

return false;

}

private boolean moveIndexOnKeyDown(int keyCode){

if(keyCode == KeyEvent.KEYCODE_DPAD_LEFT

|| keyCode == KeyEvent.KEYCODE_DPAD_UP

|| keyCode == KeyEvent.KEYCODE_DPAD_DOWN){

mResponseIndex = INDEX_CHECKBOX;

resetDefaultBackground();

return false;

}

else if(keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){

if(mResponseIndex == INDEX_SETTINGBTN){

mResponseIndex = INDEX_CHECKBOX;

resetDefaultBackground();

return false;

}

else{

mResponseIndex = INDEX_SETTINGBTN;

mSettingBtn.setBackgroundResource(R.drawable.appwidget_item_bg_pressed);

mSettingBtn.invalidate();

mTextLayout.setBackgroundResource(R.drawable.appwidget_item_bg_normal);

mTextLayout.invalidate();

return true;

}

}

else if(keyCode == KeyEvent.KEYCODE_ENTER){

if(mResponseIndex == INDEX_CHECKBOX){

checkBoxOption();

}

else if(mResponseIndex == INDEX_SETTINGBTN){

startShowSetting();

}

return true;

}

else{

return false;

}

}

/*一般View的话,可以直接XXX. setOnKeyListener(XXX),在Setting中大量的用到PreferenceFragment,其

内部镶嵌了一个listview,因此对一个PreferenceFragment的操作,其实是对该listview的操作,所以需要设这

该listview的keyListener*/

ListView listView = getListView();

listView.setOnKeyListener(mCheckboxKeyListenner);

step 2:在能捕获按键之后,需要做的自己来做焦点的逻辑管理

实例一:

//收集自己打算管理的view的数组

private void colloctionViews(){

mViews = new View[NEEDVIEWS_SIZE];

mViews[0] = mYearSpinnerInput;

mViews[1] = mMonthSpinnerInput;

mViews[2] = mDaySpinnerInput;

}

//焦点的移动对View的逻辑来说其实就是数组的下标的管理

private void increaseCurIndex(){

mLastIndex = mCurrentIndex;

mCurrentIndex = (mCurrentIndex + 1) % mViews.length;

}

private void decreaseCurIndex(){

mLastIndex = mCurrentIndex;

if(mCurrentIndex == 0){

mCurrentIndex = mViews.length - 1;

}

else{

mCurrentIndex--;

}

}

//对按键的响应来改变的焦点主要是改变View的索引flag,然后对对应的view的高亮进行重绘

public boolean onKeyDown(int keyCode, KeyEvent event){

if(KeyEvent.KEYCODE_DPAD_LEFT == keyCode){

decreaseCurIndex();

mViews[mCurrentIndex].requestFocus();

updateBackground();

return true;

}

else if(KeyEvent.KEYCODE_DPAD_RIGHT == keyCode){

increaseCurIndex();

mViews[mCurrentIndex].requestFocus();

updateBackground();

return true;

}

else{

}

return false;

}

Step3:接下来是对当前焦点的高亮进行重绘

实例一:

//对响应的view调用invalidate(),便能触发其对焦点高亮进行重绘,当然这里需要mIsOnFocus来作为高亮

//打开和关闭的开关

@Override

protected void onDraw (Canvas canvas){

super.onDraw(canvas);

if(mIsOnFocus){

// 或者使用drawBoundsOfKey(canvas);

drawFocusBackground();

}

}

在上面的drawFocusBackground其实会遇到两种情况

情况一为:直接对当前view进行高亮边框的绘制,你能直接拿到它的canvas进行绘制,那么重绘代码如下:

实例一:

//直接在外部绘制高亮矩形

private void drawBoundsOfKey(Canvas canvas){

Paint p = new Paint();

p.setColor(Color.CYAN);

p.setStyle(p.getStyle().STROKE);

p.setStrokeWidth(3.75f);

focusedKey = mSoftKeyboard.getKeys().get(mLastKeyIndex);

rect = new Rect(focusedKey.mLeft, focusedKey.mTop,

focusedKey.mRight, focusedKey.mBottom);

canvas.drawRect(rect, p);

}

情况二为:绘制的是内部一些子View的高亮边框进行重绘,这个时候你拿不到它canvas进行绘制,那么重绘可以通过设置背景色的方式来达到高亮提示的效果,重绘代码如下:

实例二:

//需要保存旧的drawable来做清除焦点的动作

private void drawFocusBackground(){

View curView = mViews[mCurrentIndex];

mOldDrawable = curView.getBackground();

curView.setBackgroundColor(0xAA07FFFF);

curView.invalidate();

}

private void rebackOldBackground(){

View oldView = mViews[mLastIndex];

oldView.setBackgroundDrawable(mOldDrawable);

oldView.invalidate();

oldView.clearFocus();

}

Step4:最后一步便是按下enter键的时候的功能响应

思路一:对一个View的功能响应,其实可以对该view进行一次模拟的touch事件,这样能让系统自己走touch该view的功能流程,达到思路最简单,代码最少的目的

实例一:

//这里的view需要给出你需要响应的View。而构造的点击中心点普通的view的话设定为view的中心便可

//以了,如果是edit类的view,或许你的点击中心点应当在它的focusRect()

private void emulateTouchEvent(int left, int top, int right, int bottom, View v){

final int x = left + (right - left) / 2;

final int y = top + (bottom - top) / 2;

final long downTime = SystemClock.uptimeMillis();

final MotionEvent downEvent = MotionEvent.obtain(

downTime, downTime, MotionEvent.ACTION_DOWN, x, y, 0);

final MotionEvent upEvent = MotionEvent.obtain(

downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, x, y, 0);

v.onTouchEvent(downEvent);

v.onTouchEvent(upEvent);

downEvent.recycle();

upEvent.recycle();

}

思路二:查看代码,看这个view响应的功能函数是什么,直接对功能函数进行调用 PS:注释使用了两种风格,不好看,下次得注意了;吐个槽:这CSDN的排版功能不是一般的难用啊

android apk对遥控器支持,Android中关于APK对遥控器支持的修改相关推荐

  1. android qq apk,仿QQ获取手机中的APK并分享的实现

    前几天看到同事里有一个界面绚丽的应用,觉得有点意思,就让他把APK发给我,我想反编译看看里面的代码.结果,这哥们在手机里找了好一阵子,最后给我说:手机没有root,找不到APK文件在哪里.我再让他试试 ...

  2. mysql不支持union_Mysql中Union的子句不支持order by

    问题是这样的,我打算在一个表里获得与某一行记录相邻的两行,并且想通过union一起取出来,所以这么写: select id,title from subjects where id>#some_ ...

  3. 【Android 安全】DEX 加密 ( Java 工具开发 | apk 文件签名 )

    文章目录 一.生成 jks 文件 二.签名命令 三.执行结果 四.处理 Unsupported major.minor version 52.0 错误 参考博客 : [Android 安全]DEX 加 ...

  4. 【多图】Google工程师解析Android系统架构--what is android(转载)

    导读:Sans Serif是Google的一位工程师,近日发布了一篇博文非常清楚的描述了Android系统架构,中国移动通信研究院院长黄晓庆在新浪微博上推荐了该文,并认为文中对Android的介绍很好 ...

  5. Unity接入Android广告: 三、Android端接入小米广告SDK

    1.导入小米广告SDK SDK在 小米开发者平台 中可以下载 导入MimoSdk.jar,右击jar包,Add As Library 在Module的AndroidManifest.xml中加入SDK ...

  6. android分屏资源适配,Android N 分屏适配

    支持和禁止分屏功能 android:resizeableActivity="true|false" 通过AndroidManifest中进行配置,来支持或者禁止分屏功能 监听是否进 ...

  7. Android wifi密码 源码,Android 修改WiFi热点的默认SSID和密码

    修改以下代码: fraeworks\base\wifi\java\android\net\wifi下面wifiApConfigStore.Java中的 loadApConfiguration() { ...

  8. 读取asserts 文件中的apk

    读取asserts 文件中的apk 任务需要,需要读取asserts文件夹中的apk文件并读取其版本信息和大小,完成后整理如下: 学习借鉴的网址: 1.https://blog.csdn.net/w0 ...

  9. Android中关于APK文件的下载、安装和卸载

    如果我们想开发一款App,而这款App的需求中有对Apk文件的下载.安装和卸载功能的话(就像豌豆荚,当然功能不会那强大,因为强大的功能背后总是一些比较NB的技术在支持),那么这篇博客还是比较适合你的. ...

  10. Android中的APK,TASK,PROCESS,USERID之间的关系

    开发Android已经有一段时间了,今天接触到底层的东西,所以对于进程,用户的id以及Android中的Task,Apk之间的关系,要做一个研究,下面就是研究结果: apk一般占一个dalvik,一个 ...

最新文章

  1. 密码错误Neo.ClientError.Security.Unauthorized: The client is unauthorized due to authentication failure
  2. WebDriver 登陆 Jsoup抓取内容
  3. 串口调试神器之Docklight
  4. 求两个数组的最长重复子数组 Maximum Length of Repeated Subarray
  5. SUMO 在LINUX 下安装以及环境变量的配置
  6. 互联网1分钟 |1109
  7. 【HNOI2006】鬼谷子的钱袋
  8. php按数字分页类,PHP简单实现数字分页功能示例
  9. 金山词霸2009牛津版完整破解版+绿色精简版下载
  10. 使用plsql导出数据库表中数据
  11. java pdf添加图片_Java 给 PDF 设置背景图片
  12. POJ3080 基本字符串库函数的应用 ..Brute Force/朴素模式匹配算法
  13. 内存不能为read或written的解决方案
  14. 计算机管理为什么没有端口,Win7设备管理器没有端口选项的三大原因及解决措施...
  15. 计算机专业的文献翻译,计算机专业外文文献翻译
  16. 免费下载学术文献的网站,好用!
  17. Vue 3 之什么是 解包
  18. 苹果频率测试软件gen,【技术干货】进行精准的PCIe 4.0时钟抖动测量
  19. 知识产权公证业务构成
  20. Java 翻转字符串 将字符串逆序

热门文章

  1. 天津出差系列(七)----第七天
  2. vue根据url获取内容axios_使用Vue.js和Axios从第三方API获取数据 — SitePoint
  3. 功能室计算机宣言,教室布置标语(精选多篇)
  4. 兴安雪学运维之:CentOS用户管理命令详解之一
  5. 读书笔记--交流电的瞬时值和有效值
  6. 学习倍福BECKHOFF PLC可利用的资源
  7. 2048小游戏源代码
  8. 02 Redis 底层数据结构
  9. MySQL自定义中文转拼音函数
  10. 易飞软件乱码显示不正常