1?概述
嘗試在App層直接讀取驅動的Input?Event,獲取觸屏事件(本文獲取的是電磁筆觸屏事件),而不通過Android的Input?Framework.?
2?架構
3?實現
3.1?JNI層
共有以下幾個文件:
?![](https://img-blog.csdn.net/20141229111141640?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQveG53eWQ=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
3.1.1?input_pen.h
android jni開發、首先看input_pen.h?
- #ifndef?_INPUT_PEN_H??
- #define?_INPUT_PEN_H??
- ???
- ???
- #include?<pthread.h>??
- #include?<linux/input.h>??
- #include?<sys/types.h>??
- #include?<linux/types.h>??
- ???
- #ifdef?_cplusplus??
- extern?"C"?{??
- #endif??
- ???
- ??
- ????typedef?void?(*get_event_callback)(__u16?type,?__u16?code,?__s32?value?);??
- ???
- ??
- ????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;??
- ???
- ??????
- ??
- ???
- ??
- ????unsigned?char?input_pen_init(input_callback?*callback);??
- ???
- ??
- ????void?input_pen_exit();??
- ???
- ???
- ??
- ???
- ???
- #ifdef?_cplusplus??
- }??
- #endif??
- ???
- #endif??
- ???
- ? ?
3.1.2?input_pen.cpp
- #include?<pthread.h>??
- #include?<stdio.h>??
- #include?<stdlib.h>??
- #include?<errno.h>??
- #include?<string.h>??
- #include?<unistd.h>??
- #include?<fcntl.h>??
- #include?<sys/types.h>??
- #include?<sys/epoll.h>??
- #include?<sys/wait.h>??
- #include?<sys/un.h>??
- #include?<stddef.h>??
- #include?<linux/input.h>??
- ???
- #include?"input_pen.h"??
- #include?"debug.h"??
- ???
- ???
- ???
- ??
- #define?DEV_PATH?"/dev/input/event1"??
- ???
- ??
- #define?MAX_EVENTS?1??
- ???
- ??
- #define?EPOLL_SLEEP?200??
- ???
- ??
- #define?USING_PTHREAD?0??
- ???
- ???
- #if?USING_PTHREAD??
- #define?LOGD(fmt,?arg...)?do{printf(fmt"\n",?##arg);}while(0)??
- #define?LOGE?LOGD??
- #endif??
- ???
- ??
- ???
- ??
- ???
- ??
- static?int?fd?=?0;??
- ??
- static?int?epoll_fd?=?0;??
- ??
- 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;??
- ???
- ??
- ???
- ???
- ??
- static?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;??
- }??
- ???
- ??
- static?void?epoll_register(?int??epoll_fd,?int??fd?)?{??
- ????struct?epoll_event??ev;??
- ????int?????????ret;??
- ???
- ????ev.events??=?EPOLLIN;??
- ????ev.data.fd?=?fd;??
- ???
- ????do?{??
- ??????????
- ????????ret?=?epoll_ctl(?epoll_fd,?EPOLL_CTL_ADD,?fd,?&ev?);??
- ????}?while?(ret?<?0?&&?errno?==?EINTR);??
- ???
- }??
- ???
- ???
- ???
- ??
- static?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(fd);??
- ???
- ??????????
- ????????fd?=?0;??
- ????????epoll_fd?=?0;??
- ????????start_flag?=?0;??
- ????????exit_flag?=?0;??
- ??????????
- ????????if?(callbacks?!=?NULL?&&?callbacks->detach_thread_cb?!=?NULL)?{??
- ????????????callbacks->detach_thread_cb();??
- ????????????LOGD("callbacks->detach_thread_cb();\n");??
- ????????}??
- ???
- ??????????
- ????????pthread_exit(NULL);??
- ???
- ???
- ????}??
- }??
- ???
- ???
- ??
- #if?USING_PTHREAD??
- static?void?*run(void?*args)?{??
- #else??
- static?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)??
- ??????????????????
- ????????????????if?(callbacks?!=?NULL?&&?callbacks->get_event_cb?!=?NULL)?{??
- ????????????????????callbacks->get_event_cb(event.type,?event.code,?event.value);??
- ????????????????}??
- #else??
- ??????????????????
- ????????????????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?=?cb;??
- ???
- ??????
- ????fd?=?open(DEV_PATH,?O_RDWR);??
- ????if?(fd?<?0)?{??
- ????????LOGE("open?device?failed!\n");??
- ????????return?0;??
- ????}??
- ???
- ??????
- ????epoll_fd?=?epoll_create(MAX_EVENTS);??
- ????if?(epoll_fd?==?-1)?{??
- ????????LOGE("epoll_create?failed!\n");??
- ????????return?0;??
- ????}??
- ??????
- ????set_non_blocking(fd);??
- ???
- ??????
- ????epoll_register(epoll_fd,?fd);??
- ???
- ??????
- ????if?(pthread_mutex_init(&exit_mutex,?NULL)?!=?0)?{??
- ????????LOGE("pthread_mutex_initn?failed!");??
- ????????return?0;??
- ????}??
- ???
- ??????
- #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_PTHREAD??
- int?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?<stdlib.h>??
- #include?<malloc.h>??
- #include?<jni.h>??
- #include?<JNIHelp.h>??
- #include?<utils/Log.h>??
- #include?"android_runtime/AndroidRuntime.h"??
- ???
- #include?"input_pen.h"??
- #include?"debug.h"??
- ???
- ??
- #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();??
- ????}??
- }??
- ???
- ??
- static?void?GetEventCallback(__u16?type,?__u16?code,?__s32?value)?{??
- ????JNIEnv*?env?=?AndroidRuntime::getJNIEnv();??
- ??????
- ????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,??
- };??
- ???
- ??
- 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;??
- ??????
- ????clazz?=?env->FindClass(kClassName);??
- ????if?(clazz?==?NULL)?{??
- ????????LOGE("Can't?find?class?%s/n",?kClassName);??
- ????????return?-1;??
- ????}??
- ??????
- ????if?(env->RegisterNatives(clazz,gMethods,sizeof(gMethods)/sizeof(gMethods[0]))?!=?JNI_OK)?{??
- ????????LOGE("Failed?registering?methods?for?%s/n",?kClassName);??
- ????????return?-1;??
- ????}??
- ??????
- ????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;??
- ????}??
- ??????
- ????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.cpp??
- ??????
- LOCAL_MODULE_TAGS?:=?optional??
- ??
- LOCAL_SHARED_LIBRARIES?:=?liblog?libcutils?libandroid_runtime?libnativehelper??
- LOCAL_PRELINK_MODULE?:=?false??
- ??
- LOCAL_MODULE:=?libinput_pen??
- include?$(BUILD_SHARED_LIBRARY)??
- ??
- ??
- ??
- ??
1.1.1?Debug.h
- #ifndef?_DEBUG_H??
- #define?_DEBUG_H??
- ???
- #include?<utils/Log.h>??
- ???
- #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;??
- ???
- ??????
- ????private?int?action;??
- ??????
- ????private?float?x;??
- ??????
- ????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
3.2.3?Activity
獲取更新驅動程序和可選功能,Activity可以通過調用InputPen的start函數,啟動讀取線程,再調用setHandler設置Handler,從而就可在Handler中處理PenEvent數據了。