上篇文章《Android AccessibilityService拦截事件及VR眼镜返回按键捕捉》我们介绍了如何用AccessibilityService来拦截事件。
本篇我们来介绍另一种拦截按键的方式,就是在shell的状态下,使用getevent命令对输入事件进行分析。必须要说明的是getevent命令使用场景有:
1.在PC端shell环境下,不必root
2.在APP端使用必须要root权限
package com.jason.btnmonitor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initMonitor();
Button get = (Button) findViewById(R.id.get);
Button start = (Button) findViewById(R.id.start);
Button stop = (Button) findViewById(R.id.stop);
get.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getDevices();
}
});
start.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
startMonitor();
}
});
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
stopMonitor();
}
});
}private void getDevices(){
BtnMonitorController.getInstance().getVRDevice();
}private void initMonitor(){
BtnMonitorController.getInstance().init();
}public void startMonitor(){BtnMonitorController.getInstance().start();
}public void stopMonitor(){BtnMonitorController.getInstance().stop();
}private void releaseMonitor(){
BtnMonitorController.getInstance().release();
}@Override
protected void onDestroy() {
super.onDestroy();
releaseMonitor();
}
}
MainActivity的实现。 【Android|Android getevent拦截输入事件】
layout的实现。
package com.jason.btnmonitor;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.stericson.RootTools.RootTools;
import com.stericson.RootTools.exceptions.RootDeniedException;
import com.stericson.RootTools.execution.Command;
import com.stericson.RootTools.execution.Shell;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class BtnMonitorController {private static final String COMMAND_GET_DEVICE_VR = "getevent";
private static final String COMMAND_GET_VR_EVENT = "getevent -l -t ";
public static final int MSG_EVENT_INPUT = 9000;
private String deviceName="/dev/input/event19";
//demo监听的是event19,这里可以改为你所要监听的eventprivate static boolean isMonitorStart = false;
private static boolean hasVR = false;
private Shell shell;
private Command command;
private Handler handler;
private static BtnMonitorController instance ;
private BtnMonitorController(){}public static BtnMonitorController getInstance(){
if (instance == null) {
synchronized (BtnMonitorController.class){
if (instance == null) {
instance = new BtnMonitorController() ;
}
}
}
return instance ;
}public void init(){
try {
shell = RootTools.getShell(true);
//getevent命令必须要root
} catch (IOException e) {
e.printStackTrace();
LogUtil.e("shell init error");
} catch (TimeoutException e) {
e.printStackTrace();
LogUtil.e("shell init error");
} catch (RootDeniedException e) {
e.printStackTrace();
LogUtil.e("shell init error");
}handler = new Handler() {public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_EVENT_INPUT:LogUtil.i(""+msg.obj);
break;
}
super.handleMessage(msg);
}
};
}
//getVRDevice会输出你的inputdevice的列表,选中你想要监听的设备,替换deviceName
public void getVRDevice(){
LogUtil.i("BtnMonitor getVRDevice" );
if(isMonitorStart){
LogUtil.e("BtnMonitor is started already!");
return;
}
startCMD(COMMAND_GET_DEVICE_VR);
}public void start(){LogUtil.i("BtnMonitor start" );
if(isMonitorStart){
LogUtil.e("BtnMonitor is started already!");
return;
}startCMD(COMMAND_GET_VR_EVENT+deviceName);
}public void stop(){
LogUtil.i("BtnMonitor stop" );
if(command.isFinished()){
LogUtil.e("BtnMonitor is stopped already!");
return;
}command.terminate("stop");
}public void release(){
LogUtil.i("BtnMonitor release" );
if(handler != null && handler.hasMessages(MSG_EVENT_INPUT)){
handler.removeMessages(MSG_EVENT_INPUT);
handler = null;
}if(isMonitorStart){
command.terminate("exit");
isMonitorStart = false;
}try {
if(shell != null)
shell.close();
} catch (IOException e) {
e.printStackTrace();
LogUtil.e("shell close IOException");
}}private void startCMD(String cmd){isMonitorStart = true;
command = new Command(0, 0, cmd) {
@Override
public void output(int id, String line) {
LogUtil.e("MainActivity.java:output, id:" + id + ", output:" + line);
Message m = new Message();
m.what = MSG_EVENT_INPUT;
m.obj = line + "\n";
handler.sendMessage(m);
}@Override
public void commandCompleted(int arg0, int arg1) {
// TODO Auto-generated method stub
LogUtil.e("MainActivity.java:commandCompleted, arg0:" + arg0 + ", arg1:" + arg1);
Message m = new Message();
m.what = MSG_EVENT_INPUT;
m.obj = "commandCompleted\n" + "================================\n";
handler.sendMessage(m);
isMonitorStart = false;
}@Override
public void commandOutput(int arg0, String arg1) {
// TODO Auto-generated method stub
LogUtil.e( "MainActivity.java:commandOutput, arg0:" + arg0 + ", arg1:" + arg1);
Message m = new Message();
m.what = MSG_EVENT_INPUT;
m.obj = "commandOutput, arg0:" + arg0 + ", arg1:" + arg1 + "\n";
handler.sendMessage(m);
}@Override
public void commandTerminated(int arg0, String arg1) {
// TODO Auto-generated method stub
LogUtil.e("MainActivity.java:commandTerminated, arg0:" + arg0 + ", arg1:" + arg1);
Message m = new Message();
m.what = MSG_EVENT_INPUT;
m.obj = "commandTerminated, reason:" + arg1 + "\n" + "================================\n";
handler.sendMessage(m);
isMonitorStart = false;
}
};
try {
shell.add(command);
} catch (IOException e) {
e.printStackTrace();
}
}}
BtnMonitorController的实现,使用的是开源项目的RootTools。github工程地址 https://github.com/graygray/getevent.git
文章图片
$ getevent /dev/input/event19
0004 0004 00090002
0001 0111 00000001
0000 0000 00000000
0004 0004 00090002
0001 0111 00000000
0000 0000 00000000
监听到的VR设备(默认类型为鼠标)单击返回键的内容
$ getevent -l -t /dev/input/event19
[17437.061273] EV_MSCMSC_SCAN00090002
[17437.061273] EV_KEYBTN_RIGHTDOWN
[17437.061273] EV_SYNSYN_REPORT00000000
[17437.156346] EV_MSCMSC_SCAN00090002
[17437.156346] EV_KEYBTN_RIGHTUP
[17437.156346] EV_SYNSYN_REPORT00000000
[17444.748923] EV_MSCMSC_SCAN00090002
[17444.748923] EV_KEYBTN_RIGHTDOWN
[17444.748923] EV_SYNSYN_REPORT00000000
[17446.244327] EV_MSCMSC_SCAN00090002
[17446.244327] EV_KEYBTN_RIGHTUP
[17446.244327] EV_SYNSYN_REPORT00000000
监听到的VR设备(默认类型为鼠标)返回键长按的内容,-t加上了时间戳用于判断是否是长按
针对收到的message内容可以判断BACK键的单击和长按。