前言
这一周又遇到个麻烦事儿,公司对接了一个老外客户,要求在现有的USDK密码键盘界面自定义密码界面风格,但密码按键的处理以及获取密码数据需要USDK去实现,也就是说老外只负责画界面,把绘制出的界面中的控件坐标传下来(控件的左上角和右下即角坐标),不处理点击事件,让USDK把click事件屏蔽并返回密码数据给他们(这需求也是没谁了~~无力吐槽),so开动吧!谁让我是苦逼的程序猿呢~
正文
首先我们先整理下需要做的事儿:
- 如何屏蔽应用层点击事件并获取点击的位置;
- 考虑到交互的安全性,输入密码界面需屏蔽最近任务键,Home键,Back键以及下拉任务栏;
针对上面问题1,我首先想到的是setOnTouchListener方法,获取点击的位置不正合适吗?可问题来了,不是一个进程的如何获取到界面的MotionEvent方法呢?那我可以在USDK中添加一个空白的View上去,这样不久可以获取了吗?而且通过设置View的属性也正好可以消耗点击事件,一举两得呀~至于问题2,这个修改系统就OK了,so方案有了:
- 添加透明空白View,通过setOnTouchListener方法获取用户点击位置;
- 修改系统,找到Home键,Back键以及下拉任务栏的事件处理位置,使用SystemProperties类设置自定义系统属性,在事件处理位置截取判断使能即可;
获取点击位置坐标
这里我定义了一个空的View,layout文件如下:代码块
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/offlinepin_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@android:color/transparent">
<!--显示透明View可见 方便调试,后续调试OK屏蔽即可-->
<TextView
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="test"/>
</LinearLayout>
这里通过设置android:background="@android:color/transparent" 将其设置为透明;然后在USDK中添加本View,主要代码如下:代码块
LinearLayout mLayout = (LinearLayout) LayoutInflater.from(TopwiseApplication.getContext()).
inflate(R.layout.view_offlinepin, null);
WindowManager.LayoutParams params = new WindowManager.LayoutParams();
// 设置框口属性为系统提示级别,属于最上层显示
params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
// 设置View颜色支持属性
params.format = PixelFormat.RGBA_8888;
params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
//宽 高显示限制
params.width = WindowManager.LayoutParams.MATCH_PARENT;
params.height = WindowManager.LayoutParams.MATCH_PARENT;
SDKLog.d(TAG, "addView");
//if (manager != null) {
// manager.addView(layout, params);
// isAddView = true;
//}
mHandler = new ViewHandler(mWindowManager, mLayout, params);
此处先获取layout实例,通过WindowManager服务去addView,WindowManager可通过mWindowManager = (WindowManager) TopwiseApplication.getContext().
getSystemService(Context.WINDOW_SERVICE);获取;
解释下WindowManager.LayoutParams布局属性,此属性用于设置当前添加的View的显示,活动包括事件处理等相关配置,其中flags值比较重要,介绍几个常用的:
FLAG_ALLOW_LOCK_WHILE_SCREEN_ON
//Constant Value: 1 (0x00000001)
只要这个window对用户是可见的,则允许在屏幕开启的时候锁定屏幕
这个flag可以单独的使用,也可以配合FLAG_KEEP_SCREEN_ON和(或者) FLAG_SHOW_WHEN_LOCKED使用
FLAG_DIM_BEHIND
//Constant Value: 2 (0x00000002)
所有在这个window之后的会变暗,
使用dimAmount属性来控制变暗的程度(1.0不透明,0.0完全透明)
FLAG_NOT_FOCUSABLE
//Constant Value: 8 (0x00000008)
设置之后window永远不会获取焦点,所以用户不能给此window发送点击事件
焦点会传递给在其下面的可获取焦点的window
这个flag同时会启用 FLAG_NOT_TOUCH_MODAL flag , 不管你有没有手动设置
设置这个flag同时表明了这个window不会和软键盘交互
FLAG_NOT_TOUCHABLE
//Constant Value: 16 (0x00000010)
这个window永远无法获取点击事件
FLAG_NOT_TOUCH_MODAL
//Constant Value: 32 (0x00000020)
即使这个window是可获取焦点的,
也允许window之外点击事件传递给其他在其之后的window
如果不设置这个值