1 概述

 

尝试在App层直接读取驱动的Input Event,获取触屏事件(本文获取的是电磁笔触屏事件),而不通过AndroidInput Framework.

 

 

2 架构


Android App层通过JNI从驱动获取Input Event_第1张图片

3 实现

3.1 JNI

共有以下几个文件:

 Android App层通过JNI从驱动获取Input Event_第2张图片

3.1.1 input_pen.h

 

首先看input_pen.h

 

#ifndef _INPUT_PEN_H#define _INPUT_PEN_H  #include #include #include #include  #ifdef _cplusplusextern "C" {#endif //获取input_event数据的方法指针,由App层提供    typedef void (*get_event_callback)(__u16 type, __u16 code, __s32 value ); //创建线程的函数指针,通过Java虚拟机创建    typedef pthread_t (*create_thread_callback)(const char* name, void (*start)(void *), void* arg); //释放线程资源的函数指针    typedef int (*detach_thread_callback)(void); //回调函数结构体    typedef struct {        get_event_callback get_event_cb;        create_thread_callback create_thread_cb;        detach_thread_callback detach_thread_cb;    } input_callback;     /*******************************************************************///public methods //初始化函数    unsigned char input_pen_init(input_callback *callback); //退出函数    void input_pen_exit();  /*******************************************************************/  #ifdef _cplusplus}#endif #endif  

 

3.1.2 input_pen.cpp

 

#include #include #include #include #include #include #include #include #include #include #include #include #include  #include "input_pen.h"#include "debug.h"   //驱动路径#define DEV_PATH "/dev/input/event1" //最大侦听#define MAX_EVENTS 1 //epoll_wait的最大时间#define EPOLL_SLEEP 200 //线程是否由pthread创建,否则由JVM创建#define USING_PTHREAD 0  #if USING_PTHREAD#define LOGD(fmt, arg...) do{printf(fmt"\n", ##arg);}while(0)#define LOGE LOGD#endif /**************************************************************************************/ //static variable //当前驱动文件指针static int fd = 0;//epoll文件指针static int epoll_fd = 0;//epoll_event数组static struct epoll_event events[MAX_EVENTS];//回调函数static input_callback *callbacks = NULL; //标记线程是否已启动static unsigned char start_flag = 0;//标记线程是否已退出static unsigned char exit_flag = 0;//线程锁static pthread_mutex_t exit_mutex; /**************************************************************************************/  //set non-blocking for fdstatic int set_non_blocking(int fd) {    int opts;     opts = fcntl(fd, F_GETFL);    if (opts < 0) {        LOGE("fcntl F_GETFL error: %s", strerror(errno));        return -1;    }    opts = (opts | O_NONBLOCK);    if (fcntl(fd, F_SETFL, opts) < 0) {        LOGE("fcntl F_SETFL error: %s", strerror(errno));        return -1;    }     return 0;} //register epoll events for fdstatic void epoll_register( int  epoll_fd, int  fd ) {    struct epoll_event  ev;    int         ret;     ev.events  = EPOLLIN;//interested in receiving data    ev.data.fd = fd;     do {        //register events for fd        ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );    } while (ret < 0 && errno == EINTR); }   //remove epoll events for fdstatic void epoll_unregister( int  epoll_fd, int  fd ) {    int  ret;    do {        ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );    } while (ret < 0 && errno == EINTR); }  //通知退出线程,由其他线程调用static void thread_cancel() {    LOGD("thread_cancel");    pthread_mutex_lock(&exit_mutex);     exit_flag = 1;     pthread_mutex_unlock(&exit_mutex);} //停止线程,由本线程调用static void thread_exit() {    unsigned char flag ;      pthread_mutex_lock(&exit_mutex);     flag = exit_flag;     pthread_mutex_unlock(&exit_mutex);     if (flag == 1) {        LOGD("thread_exit");        //close devices        close(fd);         //clean variablies        fd = 0;        epoll_fd = 0;        start_flag = 0;        exit_flag = 0;        //release thread resources        if (callbacks != NULL && callbacks->detach_thread_cb != NULL) {            callbacks->detach_thread_cb();            LOGD("callbacks->detach_thread_cb();\n");        }         //exit current thread        pthread_exit(NULL);      }}  //线程运行函数#if USING_PTHREADstatic void *run(void *args) {#elsestatic void run(void *args) { #endif    int n = 0;    int i = 0;    int res;    struct input_event event;     LOGD("run...");    while (1) {         thread_exit();//每次检测是否要退出运行          n = epoll_wait(epoll_fd, events, MAX_EVENTS, EPOLL_SLEEP);//检测是否有事件发生        if (n == -1) {            LOGE("epoll_wait error:%s", strerror(errno));            continue;        }         for (i = 0; i < n; i++) {            if (events[i].data.fd == fd) { //有读事件发生                res = read(fd, &event, sizeof(event));                if (res < (int)sizeof(event)) {                    LOGE("could not get event\n");                    continue;                } #if (!USING_PTHREAD)                //把input_event的数据回调到java层                if (callbacks != NULL && callbacks->get_event_cb != NULL) {                    callbacks->get_event_cb(event.type, event.code, event.value);                }#else                //printf("[%8ld.%06ld] ", event.time.tv_sec, event.time.tv_usec);                if (event.type == EV_ABS) {                    printf("%04x %04x %08x\n", event.type, event.code, event.value);                }#endif            }        }    }#if USING_PTHREAD    return NULL;#else    return ;#endif }  //初始化函数unsigned char input_pen_init(input_callback *cb) {     pthread_t thread;     LOGD("input_pen_init");    if (start_flag) {        return 1;    }     //callbacks    callbacks = cb;     //open device    fd = open(DEV_PATH, O_RDWR);    if (fd < 0) {        LOGE("open device failed!\n");        return 0;    }     //create epoll    epoll_fd = epoll_create(MAX_EVENTS);    if (epoll_fd == -1) {        LOGE("epoll_create failed!\n");        return 0;    }    //set non-blocking    set_non_blocking(fd);     //epoll register    epoll_register(epoll_fd, fd);     //mutex    if (pthread_mutex_init(&exit_mutex, NULL) != 0) {        LOGE("pthread_mutex_initn failed!");        return 0;    }     //create thread#if USING_PTHREAD    if (pthread_create(&thread, NULL, run, (void *)NULL) != 0) {        LOGE("pthread_create failed!\n");        return 0;    }#else    if (callbacks != NULL && callbacks->create_thread_cb != NULL) {        thread = callbacks->create_thread_cb("input_pen_thread", run, NULL);        if (thread == 0) {            LOGE("create thread failed!\n");            return 0;        }         start_flag = 1;        LOGD("input_pen_init success!");        return 1;     }#endif       return 0; } //退出函数void input_pen_exit() {    thread_cancel();} #if USING_PTHREADint main() {    int count = 0;    input_pen_init(NULL);     while (1) {        sleep(1);        count ++;        if (count == 20) {            thread_cancel();            sleep(1);            break;        }    }    return 0;}#endif    

以上的关键流程为:

 

1、open驱动文件,初始化epoll,创建线程。

2、在线程中通过epoll_wait检测事件,有事件发生则通过read函数读取驱动的input_event数据,并通过get_event_cb回调到Jav层。

 

3.1.3 com_jiagutech_input_InputPen.cpp

 

#include #include #include #include #include #include "android_runtime/AndroidRuntime.h" #include "input_pen.h"#include "debug.h" //Java类名#define CLASS_NAME "com/jiagutech/input/InputPen" using namespace android;  static jobject mCallbacksObj = NULL;static jmethodID method_get_event;  static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {    if (env->ExceptionCheck()) {        LOGE("An exception was thrown by callback '%s'.", methodName);        LOGE_EX(env);        env->ExceptionClear();    }} //获得input_event数据的回调函数static void GetEventCallback(__u16 type, __u16 code, __s32 value) {    JNIEnv* env = AndroidRuntime::getJNIEnv();    //invoke java callback method    env->CallVoidMethod(mCallbacksObj, method_get_event, type, code, value);     checkAndClearExceptionFromCallback(env, __FUNCTION__);} //创建线程的回调函数static pthread_t CreateThreadCallback(const char* name, void (*start)(void *), void* arg) {    return (pthread_t)AndroidRuntime::createJavaThread(name, start, arg);} //释放线程资源的回调函数static int DetachThreadCallback(void) {    JavaVM* vm;    jint result;     vm = AndroidRuntime::getJavaVM();    if (vm == NULL) {        LOGE("detach_thread_callback :getJavaVM failed\n");        return -1;    }     result = vm->DetachCurrentThread();    if (result != JNI_OK)        LOGE("ERROR: thread detach failed\n");    return result;}  //回调函数结构体变量static input_callback mCallbacks = {    GetEventCallback,    CreateThreadCallback,    DetachThreadCallback,}; //初始化Java的回调函数static void jni_class_init_native(JNIEnv* env, jclass clazz) {    LOGD("jni_class_init_native");     method_get_event = env->GetMethodID(clazz, "getEvent", "(III)V");  } //初始化static jboolean jni_input_pen_init(JNIEnv *env, jobject obj) {    LOGD("jni_input_pen_init");     if (!mCallbacksObj)        mCallbacksObj = env->NewGlobalRef(obj);     return  input_pen_init(&mCallbacks);}  //退出static void jni_input_pen_exit(JNIEnv *env, jobject obj) {    LOGD("jni_input_pen_exit");    input_pen_exit();} static const JNINativeMethod gMethods[] = {    { "class_init_native","()V", (void *)jni_class_init_native },    { "native_input_pen_init","()Z", (void *)jni_input_pen_init },    { "native_input_pen_exit","()V", (void *)jni_input_pen_exit },};   static int registerMethods(JNIEnv* env) {      const char* const kClassName = CLASS_NAME;    jclass clazz;    /* look up the class */    clazz = env->FindClass(kClassName);    if (clazz == NULL) {        LOGE("Can't find class %s/n", kClassName);        return -1;    }    /* register all the methods */    if (env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0])) != JNI_OK) {        LOGE("Failed registering methods for %s/n", kClassName);        return -1;    }    /* fill out the rest of the ID cache */    return 0;}  jint JNI_OnLoad(JavaVM* vm, void* reserved) {    JNIEnv* env = NULL;    jint result = -1;    LOGI("InputPen JNI_OnLoad");    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {        LOGE("ERROR: GetEnv failed/n");        goto fail;    }     if (env == NULL) {        goto fail;    }    if (registerMethods(env) != 0) {        LOGE("ERROR: PlatformLibrary native registration failed/n");        goto fail;    }    /* success -- return valid version number */    result = JNI_VERSION_1_4;fail:    return result;}   


3.1.4 Android.mk

LOCAL_PATH:= $(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES:= \input_pen.cpp \com_jiagutech_input_InputPen.cppLOCAL_MODULE_TAGS := optionalLOCAL_SHARED_LIBRARIES := liblog libcutils libandroid_runtime libnativehelperLOCAL_PRELINK_MODULE := falseLOCAL_MODULE:= libinput_peninclude $(BUILD_SHARED_LIBRARY)#LOCAL_MODULE:=inputpen#include $(BUILD_EXECUTABLE) 


1.1.1 Debug.h

 

#ifndef _DEBUG_H#define _DEBUG_H #include  #ifdef ALOGD#define LOGD      ALOGD#endif#ifdef ALOGV#define LOGV      ALOGV#endif#ifdef ALOGE#define LOGE      ALOGE#endif#ifdef ALOGI#define LOGI      ALOGI#endif #define LOG_TAG "InputPen" #endif   



3.2 App

共有两个文件:

PenEvent.java

InputPen.java

 

3.2.1 PenEvent.java

 

package com.jiagutech.input; public class PenEvent {      public PenEvent() {     }     public final static int ACTION_DOWN = 0x0;    public final static int ACTION_UP = 0x1;    public final static int ACTION_MOVE = 0x2;     //表示事件类型,down/up/move    private int action;    //x轴坐标    private float x;    //y轴坐标    private float y;    //压力数据    private float pressure;     public void setAction(int action) {        this.action = action;    }     public int getAction() {        return action;    }      public void setX(float x) {        this.x = x;    }     public float getX() {        return x;    }      public void setY(float y) {        this.y = y;    }     public float getY() {        return y;    }     public void setPressure(float p) {        this.pressure = p;    }     public float getPressure() {        return pressure;    }   }  

3.2.2 InputPen.java

package com.jiagutech.input; import java.util.LinkedList; import android.os.Handler;  public class InputPen {     /**********************************************************************************/    private static InputPen instance = null;     private boolean mStarted = false;     private final static String TAG = "InputPen";     //主线程Handler    private Handler mHandler = null;    //PenEvent列表    private LinkedList mEventList = new LinkedList();    //锁    private Object mListLock = new Object();     /*******************************************************************/    //以下定义请参考input_event.h文件    private final static int EV_SYN = 0x0;    private final static int EV_KEY = 0x01;     private final static int EV_ABS = 0x03;      private final static int  ABS_X = 0x00;    private final static int  ABS_Y = 0x01;    private final static int  ABS_PRESSURE = 0x18;    private final static int  BTN_TOUCH = 0x14a;    private final static int  BTN_TOOL_PEN = 0x140;    private final static int  BTN_STYLUS = 0x14b;    /*******************************************************************/    //原始的x最大分辨率    private static final float MAX_X = 15360.0f;    //屏幕x最大分辨率    private static final float MAX_X_STANDARD = 1280.0f;     //原始的y最大分辨率    private static final float MAX_Y = 9600.0f;    //屏幕y最大分辨率    private static final float MAX_Y_STANDARD = 800.0f;     //原始的最大压力数据    private static final float MAX_PRESSURE = 1023.0f;    //Android标准最大压力数据    private static final float MAX_PRESSURE_STANDARD= 1.0f;     private int _x=-1,_y=-1,_pressure=-1;    private int _bintouch = 0, _lastBinTouch = 0;    //x轴转换系数    private float xScale = MAX_X_STANDARD / MAX_X;    //y轴转换系数    private float yScale = MAX_Y_STANDARD / MAX_Y;    //压力值转换系统    private float pScale = MAX_PRESSURE_STANDARD / MAX_PRESSURE;     //y轴便宜    private float yOffset = 73.0f;     /**     * 加载libinput_pen.so,并初始化回调函数     */    static {        try {            System.loadLibrary("input_pen");            class_init_native();          } catch (UnsatisfiedLinkError e) {            e.printStackTrace();        }     }     private InputPen() {    }     /**     * 单例模式     * @return     */    public static synchronized InputPen getInstance() {        if (instance == null) {            instance = new InputPen();        }        return instance;    }     /**     * 通知主线程获取PenEvent进行处理     *     */    private void onPenTouch() {        if (mHandler != null) {            mHandler.sendEmptyMessage(0);        }     }     /**     * 设置主线程handler     * @param handler     */    public void setHandler(Handler handler) {        mHandler = handler;    }     /**     * 添加PenEvent到list     * @param event     */    private void addPenEvent(PenEvent event) {        synchronized (mListLock) {            mEventList.add(event);        }    }     /**     * 从list获取最旧的PenEvent     * @return     */    public PenEvent getPenEvent() {        PenEvent event = null;        synchronized (mListLock) {            if (mEventList.size() > 0) {                event = mEventList.removeFirst();            }        }         return event;    }      /*******************************************************************/    //public method     /**     * 坐标转换,并生成PenEvent数据     * @param event     */    protected void transform(PenEvent event) {        float x = MAX_Y_STANDARD - ((float)_y) * yScale;        float y = (float)_x * xScale - yOffset;        float p = (float)_pressure * pScale;        event.setX(x);        event.setY(y);        event.setPressure(p);    }     /**     * 处理input_event数据     */    protected void processEvent() {         if (_bintouch != _lastBinTouch ) {            _lastBinTouch = _bintouch;            //Log.d(TAG, String.format("x=%d,y=%d,pressure=%d,bintouch=%d", _x,_y,_pressure,_bintouch));            if (_bintouch == 1) { //down事件                PenEvent event = new PenEvent();                event.setAction(PenEvent.ACTION_DOWN);                transform(event);                addPenEvent(event);                onPenTouch();             } else { //up事件                PenEvent event = new PenEvent();                event.setAction(PenEvent.ACTION_UP);                transform(event);                addPenEvent(event);                onPenTouch();            }        } else if (_bintouch == 1) { //move事件            PenEvent event = new PenEvent();            event.setAction(PenEvent.ACTION_MOVE);            transform(event);            addPenEvent(event);            onPenTouch();         }        }     /**     * 获取input_event数据,由jni层调用此函数     * @param type     * @param code     * @param value     */    protected void getEvent(int type, int code, int value) {        switch (type) {         case EV_SYN:            processEvent();            break;         case EV_KEY:            if (code == BTN_TOUCH) {                _bintouch = value;            }            break;        case EV_ABS:            if (code == ABS_X) {                _x = value;            } else if (code == ABS_Y) {                _y = value;            } else if (code == ABS_PRESSURE) {                _pressure = value;            }            break;        default:            break;        }    }     /**     * 启动线程     */    protected void start() {        if (!mStarted) {            if (native_input_pen_init()) {                mStarted = true;            }         }      }     /**     * 停止线程     */    protected void stop() {        if (mStarted) {            native_input_pen_exit();            mStarted = false;        }     }     public void dispose() {        stop();    }     @Override    protected void finalize() throws Throwable {         stop();        // TODO Auto-generated method stub        super.finalize();    }      /*******************************************************************/    //native method    protected  static native void class_init_native();     protected  native boolean native_input_pen_init();     protected  native void native_input_pen_exit();}   


3.2.3 Activity

Activity可以通过调用InputPenstart函数,启动读取线程,再调用setHandler设置Handler,从而就可在Handler中处理PenEvent数据了。


更多相关文章

  1. android 存储数据与文件
  2. Android读取JSON格式数据
  3. Android通过Http连接MySQL 实现登陆/注册(数据库+服务器+客户端)
  4. Android Day03-SQLite数据库操作及ListView详解
  5. Android联系人数据库全解析-2.0以上
  6. android 线程 synchronized关键字

随机推荐

  1. Android之Android触摸事件传递机制
  2. android存储空间的检测
  3. activity的android:name所指的Activity实
  4. Android下如何获取Mac地址
  5. Android MediaScanner 详尽分析
  6. 取WiFi MAC地址
  7. Android控件之ImageView(显示图片的控件)
  8. Android button设置height后圆角消失问题
  9. Android网络操作
  10. 反抗金山毒霸的代码