LED硬件访问服务(2)——JNI/HAL
一、系统编程
1.SystemServer.java类中提供了main()方法,说明它是以一个进程的方式存在的,启动后直接执行其run()
2.注册服务
ServiceManager.addService("vibrator", vibrator);
通过addService来告诉系统,告诉系统指的是service_manager.c表示的进程。service_manager管理着系统中的所有service。要想这些服务
能被应用程序使用,就必须要注册进service_manager中。
应用程序向service_manager查询获得某一个service。然后应用程序通过接口ILedService把对硬件操作请求发送给LedService.java,然后由
这个LedService来实现对硬件的操作。
3.AIDL文件的实现
对于一个应用程序来说,它只需要调用ioctl()去控制LED,并不需要open()和close(),因此LED的ILedService.aidl文件中的interface ILedService中
只需要实现ledIoctl()这一个函数即可。模仿IVibratorService.aidl放到对应的目录下,然后修改Android.mk文件添加:core/java/android/os/ILedService.aidl
然后执行mmm .命令系统会帮我们在根目录下的out目录下生成ILedService.java文件.
/* ILedService.aidl文件 */ package android.os; /** {@hide} */ interface ILedService { int ledControl(int which, int status); }
4.应用程序怎么使用ILedService.java
参考IVibrator的,在frameworks代码中搜索IVibratorService,然后参考SystemVibrator.java。然后对比其aidl看其怎么使用aidl中指定的
函数的。
5.Tiny412 Android 内核编译方法
$ . setenv
$ lunch full_tiny4412-eng
$ make snod //修改frameworks时使用重新生成system.img时,out/target/product/tiny4412/system.img
$ ./gen-image.sh //会在根目录下生成system.img,然后烧写它即可。
6.自动生成的ILedService.java中的ILedService接口中有一个静态的stub类,它继承于binder类,说明它里面一定实现了binder进程间通信。
7.无论是addService还是getService还是应用程序执行某个service都会涉及到进程间通信。
8.参考的vibrator的代码执行路径
App --> SystemVibrator.java --> VibratorService.java --> com_android_server_VibratorService.cpp --> hal --> driver
9.使用硬件访问服务后,所有的对led硬件的操作都需要通过LedSevice.java来进行。
10.LedService的注册流程
SystemServer.java中的main()直接调用了run(),在run()中:
(1)System.loadLibrary("android_servers"); //加载libandroid_servers.so,它是由onLoad.cpp和一大堆JNI文件编译而成的。
onLoad.cpp里面有一个JNI_OnLoad(),它里面为各个Service类注册了本地方法。
(2)加载完上面的C库后,会执行startOtherServices(),它会注册各个Service, 例如调用startServiceVibrator()注册Vibrator的Service。
在这个函数中先构造这个VirbateService然后调用ServiceManager.addService("vibrator", vibrator);把它注册到系统中去。注册到系统的
意思就是把这个Service告诉service_manager进程(service_manager.c)实现的。在VibratorService中实现了对native方法的调用。
11.LedService.java被系统编译
添加LedService.java后不需要修改frameworks/base/services/core/Android.mk的原因是它里面通过
LOCAL_SRC_FILES += $(call all-java-files-under,java) 把下的所有文件都包含进去了。
12.使JNI文件被系统编译
修改frameworks/base/services/core/jni/Android.mk 参考com_android_server_VibratorService.cpp添加
com_android_server_LedService.cpp
13.修改完后重新编译system.image
我们修改的aidl文件、jni文件,service文件涉及以下Android.mk,因此应该在“frameworks/base/services/”下执行mm
frameworks/base/services/core/Android.mk //一般上层的Android.mk会把下层的Android.mk包含进来,但是它没有包含
frameworks/base/services/core/jni/Android.mk
frameworks/base/services/Android.mk //它里面指定生成SystemServer.java中指定的libandroid_servers.so库
在开发板的位置:/system/lib/libandroid_servers.so
frameworks/base/services/Android.mk中:
include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk) //会编译到jni目录下的修改
include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services)) //会编译到core目录下的修改
14.修改frameworks只需要重新编译system.img即可。
执行$ mmm frameworks/base/services/ 后,make snod, 然后./gen-img.sh生成system.img
15.涉及的各个文件
(1)LedService.java
package com.android.server; import android.os.ILedService; /* 此文件的作用: 调用本地方法来操作硬件 */ public class LedService extends ILedService.Stub { private static final String TAG = "LedService"; /*只有在打印信息的时候会使用到*/ /*不要忘记加native*/ public native static int native_ledOpen(); public native static int native_ledCtrl(int which, int status); public native static int native_ledClose(); @Override public int ledControl(int which, int status) throws android.os.RemoteException { return native_ledCtrl(which, status); } public LedService() { native_ledOpen(); } }
15.向系统中注册LedService涉及的更改
(1)SystemServer.java中仿照Vibrator添加如下代码来注册LedService
仿照Vibrator添加: Slog.i(TAG, "Led Service"); led = new LedService(); ServiceManager.addService("led", led);
二、应用App编程
1.MainActivity.java中import android.os.ILedService //导入ILedService所在的包,包名由ILedService.aidl生成的ILedService.java中
的package android.os而来的。
2.编译报错找不到ILedService这个符号,AS环境中没有ILedService,因此需要包含某些类,需要将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
包含到AS工程中。
包含方法:
AS中 File --> Project Structure --> "+" --> 选中“Import JAR/AAR Package” --> next --> 输入classes.jar的路径 --> ok
然后稍等一会等系统处理完。然后可以在Project Structure中看到classes和app是属于并列的模块。
Modules
app
classes
然后还需要让app去引用classes:
Project Structure窗口中点击app --> Dependencies --> "+" --> "module dependency" --> 然后看到clases,点击ok --> 点击ok退出Project Structure窗口
为什么包含的不是framework.jar而是classes.jar的原因是Android里面运行的不是原原本本的Java程序,framework.jar是dex格式,dex格式
是Android对java文件做的一些优化。而编译代码的时候需要原生态的java文件,所以不能使用framework.jar而是使用classes.jar
3.然后还报找不到ServiceManager符号
解决:在MainActivity.java中:import android.os.ServiceManager; //ServiceManager.java中package android.os;
4.然后编译报错:
iLedService.ledControl(i, 1); 错误: 未报告的异常错误RemoteException; 必须对其进行捕获或声明以便抛出,解决:
选中这部分代码,然后Ctrl+Alt+t填充捕获异常的代码。
5.然后编译报错class.jar中方法超过64K
官网方法:https://developer.android.com/studio/build/multidex#mdex-gradle
AndroidMenifest.xml中添加:
<application android:name="android.support.multidex.MultiDexApplication" ... application> build.gradle(Module:app)中添加: defaultConfig { ... multiDexEnabled true } dependencies { ... implementation 'com.android.support:multidex:1.0.3' }
6.AS工程可以直接删除工程下的源文件而不需要做添加移出工程的操作。
7.App相关文件
(1)MainActivity.java
package com.example.mm.app_0001_led_demo; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Button; import android.view.View; import android.widget.CheckBox; import android.widget.Toast; import android.os.ILedService; //1.导入这个包 import android.os.ServiceManager; public class MainActivity extends AppCompatActivity { private boolean ledon = false; private Button button = null; private CheckBox checkBoxLed1 = null; private CheckBox checkBoxLed2 = null; private CheckBox checkBoxLed3 = null; private CheckBox checkBoxLed4 = null; private ILedService iLedService = null; class MyButtonListener implements View.OnClickListener { //OnClickListener is a inner interface of View //iLedService hradControl = new iLedService(); /* Ctrl + i auto override*/ @Override public void onClick(View v) { ledon = !ledon; if (ledon) { button.setText("ALL OFF"); checkBoxLed1.setChecked(true); checkBoxLed2.setChecked(true); checkBoxLed3.setChecked(true); checkBoxLed4.setChecked(true); try { for (int i = 0; i < 4; i++) { /*3.通过该实例直接调用aidl中的函数*/ iLedService.ledControl(i, 1); } } catch (RemoteException e) { e.printStackTrace(); } } else { button.setText("ALL ON"); checkBoxLed1.setChecked(false); checkBoxLed2.setChecked(false); checkBoxLed3.setChecked(false); checkBoxLed4.setChecked(false); try { for (int i = 0; i < 4; i++) { iLedService.ledControl(i, 0); } } catch (RemoteException e) { e.printStackTrace(); } } } } public void onCheckboxClicked(View view) { // Is the view now checked? boolean checked = ((CheckBox) view).isChecked(); try { // Check which checkbox was clicked switch(view.getId()) { case R.id.LED1: if (checked) { iLedService.ledControl(0, 1); Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show(); } else { iLedService.ledControl(0, 0); Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show(); } break; case R.id.LED2: if (checked) { iLedService.ledControl(1, 1); Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show(); } else { iLedService.ledControl(1, 0); Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show(); } break; case R.id.LED3: if (checked) { iLedService.ledControl(2, 1); Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show(); } else { iLedService.ledControl(2, 0); Toast.makeText(getApplicationContext(), "LED3 off",Toast.LENGTH_SHORT).show(); } break; case R.id.LED4: if (checked) { iLedService.ledControl(3, 1); Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show(); } else { iLedService.ledControl(3, 0); Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show(); } break; } } catch (RemoteException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /*2.获取一个ILedService的实例*/ /* name "led" should the same as the name of addService() */ iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led")); /* Ctrl+r and then replace all make iLedService-->iLedService */ button = (Button) findViewById(R.id.BUTTON); button.setOnClickListener(new MyButtonListener()); /* Ctrl + shift + Space to insert CheckBox to ()*/ checkBoxLed1 = (CheckBox) findViewById(R.id.LED1); checkBoxLed2 = (CheckBox) findViewById(R.id.LED2); checkBoxLed3 = (CheckBox) findViewById(R.id.LED3); checkBoxLed4 = (CheckBox) findViewById(R.id.LED4); } }
8.编译生成的apk竟然有7M那么大,它把class.jar直接打包进apk里面去了,若是不想包含class.jar到apk包中:
File --> Project Structure --> 选中Module下的app --> 看其dependencies --> 将class.jar的scope选项从compile修改为provided(新版本的AS选择为Compile Only).
作用是使class.jar只是用来编译,并不会把它打包到apk中。然后apk文件就只有1M多了。
三、JNI文件
1.若是没有使用HAL,那么JNI文件(C文件)直接操作硬件,若是使用了HAL文件,则JNI文件需要向上提供本地函数,向下加载HAL文件并调用HAL函数,
HAL文件来访问驱动程序执行硬件操作。
2.JNI文件和HAL文件都是使用C来写的,JNI文件加载HAL文件的实质就是怎么使用dlopen()来加载HAL文件编译成的动态库文件。
Android代码中对dlopen()做了一层封装,我们使用的是external/chromium_org/third_party/hwcplus/hardware.c中的hw_get_module()
可以在frameworks目录下搜索hw_get_module看看别人是怎么使用的,参考com_android_server_lights_LightsService.cpp
假如要相同hw_get_module("led", &module);加载HAL文件
(1)"led"如何转换为dlopen(filename)
由函数hw_module_exists()可知依次会在3个目录下查找name.subname.so:
a.环境变量HAL_LIBRARY_PATH指示的目录 //tiny4412上使用echo $HAL_LIBRARY_PATH这个环境变量为空
b./vendor/lib/hw //tiny4412上这个目录不存在
c./system/lib/hw //tiny4412上这个目录存在,因此把HAL文件库放到这个目录下。
-------------------------------------
查找的HAL库文件是led.$(prop).so文件, 其中prop来按优先级源于:
prop=property_get(ro.hardware.led或ro.hardware或ro.product.board或ro.board.platform或ro.arch)
使用getprop工具查看:
ro.hardware.led = 目前等于空
ro.hardware = tiny4412
ro.product.board = tiny4412
ro.board.platform = exynos4
ro.arch = 目前等于空
最后还会去尝试加载led.default.so文件(我们这个平台上由Android.mk控制hal生成的文件就是这个)
因此上面三个路劲下的以下名的so文件都是备选项:
led.tiny4412.so
led.exynos4.so
led.default.so
注意:如果用户设置了ro.hardware.led这个属性值为“v1”,则会最优先加载led.v1.so, 因此若有多个版本的hal文件可以使用属性控制
加载哪一个。但是属性是断电后清零的。setprop设置的属性会在系统重新上电后消失。
(2)调用dlopen是如何进行加载的
load dlopen (struct hw_module_t *)dlsym(handle, "HMI") //从so文件中获取名为HMI的hw_module_t类型的结构体 strcmp(id, hmi->id) //检验hmi->id的id是否等于"led" 函数原型如下: int hw_get_module(const char *id, const struct hw_module_t **module) void *dlopen(const char *filename, int flag);
3.总结:
(1)JNI使用HAL的方法
a.通过hw_get_module()从HAL文件中获取一个名为HMI的hw_module_t类型的结构体
b.调用这个结构体里面提供的methods->open(),通过它获取设备操作函数集合。
c.之后就可以通过函数集合里面的函数操作硬件了。
(2)与之对应的HAL的编写方法
a.在HAL文件中提供一个hw_module_t的结构体
b.提供methods->open(),通过它导出设备操作的函数集合。
4.JNI程序实现
#define LOG_TAG "LedService" #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include "jni.h" #include "JNIHelp.h" /*must contain, else build error*/ #include <utils/misc.h> #include <utils/Log.h> #include <hardware/hardware.h> #include <hardware/led_hal.h> namespace android { static led_device_t *g_device; static int init_native(led_device_t ** device) { int ret; hw_module_t *module; led_device_t *led_device; ret = hw_get_module(LED_HARDWARE_MODULE_ID, (hw_module_t const**)&module); if (ret) { ALOGE("init_native failed, ret=%d", ret); return -1; } ret = module->methods->open(module, NULL, (hw_device_t **)&led_device); if (ret < 0) { return -1; } *device = led_device; return 0; } static jint led_open(JNIEnv *env, jclass cls) { int ret; static int first = 0; if (first == 0) { first++; ret = init_native(&g_device); if (ret) { return -1; } } if (g_device) { return g_device->led_open(g_device); } else { return -1; } } static jint led_ctrl(JNIEnv * env, jclass cls, jint which, jint status) { if (g_device) { return g_device->led_ioctl(g_device, which, status); } else { return -1; } } static void led_close(JNIEnv *env, jclass cls) { if (g_device) { g_device->led_close(g_device); } } static const JNINativeMethod method_table[] = { { "native_ledOpen", "()I", (void*)led_open }, { "native_ledCtrl", "(II)I", (void*)led_ctrl }, { "native_ledClose", "()V", (void*)led_close }, }; int register_android_server_LedService(JNIEnv *env) { /*把method_table中的方法注册到类com.android.server.LedService中*/ return jniRegisterNativeMethods(env, "com/android/server/LedService", method_table, NELEM(method_table)); } };
四、HAL文件
1.编写hal文件参考:
hardware/qcom/display/msm8974/liblight/lights.c
或
hardware/libhardware/modules/vibrator/vibrator.c //vibrator的JNI文件没有使用它
2.Vibrator的文件组成
APP: AS中编写的App程序
AIDL: frameworks/base/core/java/android/os/IVibratorService.aidl
Service: frameworks/base/services/core/java/com/android/server/VibratorService.java
JNI: frameworks/base/services/core/jni/com_android_server_VibratorService.cpp
HAL:hardware/libhardware/modules/vibrator/vibrator.c
DRIVER: vibrator驱动程序
5.Hal文件的头文件存放路径
参考的lights的:hardware/libhardware/include/hardware/lights.h
hal文件中定义的一些结构需要放在头文件中,因为JNI文件中也会使用到它。
Hal文件位置:
hardware/libhardware/modules/led/led_hal.c
hardware/libhardware/include/hardware/led_hal.h
6.修改Android.mk编译led_hal.c文件
还要参考lights.c或者vibrator.c修改Android.mk使hal文件被编译
led参考的是hardware/libhardware/modules/vibrator/Android.mk 中的LOCAL_MODULE_TAGS := optional需要改为eng(表示开发版本),因为编译
的时候lunch的是eng版本。
7.然后编译,然后烧录System.img进行测试
# mmm frameworks/base/services
# mmm hardware/libhardware/modules/led
# make snod
# ./gen-img.sh
8.也就是说Android分为四块,Uboot、内核、system(framework/hardware)、data(应用程序)
9.HAL文件实现
(1)led_hal.c
#define LOG_TAG "LedHal" #include <hardware/hardware.h> #include <hardware/led_hal.h> #include <cutils/log.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/ioctl.h> #include <stdlib.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #define DEV_FILE "/dev/leds" int hal_led_open(led_device_t *device) { int fd = open(DEV_FILE, O_RDWR); if (fd < 0) { ALOGE("hal_led_open failed!"); return -1; } device->fd = fd; ALOGI("hal_led_open called"); return 0; } int hal_led_ioctl(led_device_t *device, int which, int status) { int ret; ret = ioctl(device->fd, status, which); if (ret != 0) { ALOGE("hal_led_ioctl failed: which=%d, status=%d", which, status); return -1; } ALOGI("hal_led_ioctl called: which=%d, status=%d", which, status); return 0; } /*这里传参数是hw_device_t,其它函数传参是led_device_t*/ int hal_led_close(led_device_t *device) { close(device->fd); ALOGI("hal_led_close called!"); return 0; } /* here id is device_id, when more than one device, use it to choose */ /*加上"__unused"可以防止编译器报警告:warning: unused parameter 'id' [-Wunused-parameter]*/ int led_module_open(const struct hw_module_t* module, const char* id __unused, struct hw_device_t** device) { led_device_t *led_device = calloc(1, sizeof(led_device_t)); if (!led_device) { ALOGE("Can not allocate memory for led_device"); *device = NULL; return -ENOMEM; } led_device->common.tag = HARDWARE_DEVICE_TAG; led_device->common.module = (hw_module_t *) module; led_device->common.version = HARDWARE_DEVICE_API_VERSION(1,0); //led_device->common.close = hal_led_close; led_device->led_open = hal_led_open; led_device->led_ioctl = hal_led_ioctl; led_device->led_close = hal_led_close; *device = (hw_device_t *)led_device; return 0; } static struct hw_module_methods_t led_module_methods = { .open = led_module_open, }; /*这里必须不能加static修饰,否则dlsym()找不到这个HMI结构体*/ //static hw_module_t HAL_MODULE_INFO_SYM = { struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .module_api_version = LED_API_VERSION, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = LED_HARDWARE_MODULE_ID, .name = "Led HAL of Mr.Sun", .author = "Mr.Sun", .methods = &led_module_methods, };
(2)led_hal.h
#ifndef HARDWARE_LED_HAL_H #define HARDWARE_LED_HAL_H #define LED_HARDWARE_MODULE_ID "led" #define LED_API_VERSION HARDWARE_MODULE_API_VERSION(1,0) typedef struct _led_device { struct hw_device_t common; int fd; int (*led_open)(led_device_t *device); int (*led_ioctl)(led_device_t *device, int which, int status); void (*led_close)(led_device_t *device); } led_device_t; #endif /*HARDWARE_LED_HAL_H*/
四、驱动
驱动不变,还是使用上一节的驱动。
五、时App使用反射机制操作Led
1.修改App利用反射
a.注释掉MainActivity.java中的
//import android.os.ILedService;
//import android.os.ServiceManager;
//iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
b.要使用反射来实现这个句代码:
//注意到ServiceManager是个标注为hide的方法,其getService实public static的,
Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
//第一个参数应该传入一个实例化对象,但是由于getSevice是static的并不需要,所以传入null.
IBinder ledService = getService.invoke(null, "led");
//IBinder是一个可见的接口,所以直接使用就可以了。$表示访问内部类,asInterface需要的参数是IBinder的对象
Method asInterface = Class.forName("android.os.ILedService$Stub").getMethod("asInterface", IBinder.class);
//从ILedService.java中看出,执行asInterface方法会返回一个ILedService.Stub.Proxy(obj)的对象,但是我们并没有把ILedService import到
//MainActivity.java中,因此不能直接使用这个类型。但是可以使用Object(其父类)。
//第一个参数应该是一个实例化对象,由于是asInterface是一个static方法,因此传null。
Object proxy = asInterface.invoke(null, ledService);
//之后就可以使用proxy里面的ledControl()来操作led了。
//从ILedService.java中也可以看出proxy类中实现了ledControl(), 它里面实现了通过binder驱动与LedService通信的操作。
Method ledCtl = Class.forName("android.os.ILedService$Stub$Proxy").getMethod("ledControl", int.class, int.class);
Class.forName是首先获得这个类,之后就可以使用ledCtl来设置led了。
使用ledCtl来设置led的方法:
//由于从ILedService中Proxy类中的ledControl方法并不是static的,因此参数1需要指定一个实例化对象。这个实例化对象是
ledCtl.invoke(proxy, 0, 1);
需要把proxy还有ledCtl设置为调用类的属性,也就是类MainActivity的属性,添加如下代码:
Object proxy = null;
Method ledCtl = null;
然后上面的修改再使用这两个成员的时候就可以直接使用了。
然后修改代码把所有的对led的操作都改为ledCtl.invoke(proxy, which, status);
2.编译报错找不到符号IBinder和Method
import android.os.IBinder; //IBinder.java中这样package android.os;
3.编译报错不兼容的类型: Object无法转换为IBinder
将上面:
IBinder ledService = getService.invoke(null, "led"); //相当于调用getService方法
改为:
Object ledService = getService.invoke(null, "led");
报错“Object无法转换为IBinder”也就是说getService()返回的是一个Object类型,查看ServiceManager.java源码找到getService()方法发现
其的确返回一个IBinder对象呀,为什么使用IBinder对象接收就不行呢。
注意,这里的getService是通过Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
得到的,双击这里的"Class" Shift+f1,在打开的网页中搜索getMethod,点击进入其返回值网页,在里面检索invoke,找到invoke的原型为:
"Object invoke(Object obj, Object... args)",返回的的确是一个Object类型。
总结:ServiceManager.java中的getService()的确返回一个IBinder对象,但是在调用invoke的时候就向上转化为了Object对象。而这里想让Object向下
转化为Ibinder的话就需要加IBinder进行强制类型转换。eg: IBinder ledService = (IBinder)getService.invoke(null, "led");
4.使用反射机制的MainActivity.java
package com.example.mm.app_0001_led_demo; import android.os.RemoteException; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.Button; import android.view.View; import android.widget.CheckBox; import android.widget.Toast; import android.os.IBinder; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MainActivity extends AppCompatActivity { private boolean ledon = false; private Button button = null; private CheckBox checkBoxLed1 = null; private CheckBox checkBoxLed2 = null; private CheckBox checkBoxLed3 = null; private CheckBox checkBoxLed4 = null; Object proxy = null; Method ledCtl = null; class MyButtonListener implements View.OnClickListener { //OnClickListener is a inner interface of View /* Ctrl + i auto override*/ @Override public void onClick(View v) { ledon = !ledon; if (ledon) { button.setText("ALL OFF"); checkBoxLed1.setChecked(true); checkBoxLed2.setChecked(true); checkBoxLed3.setChecked(true); checkBoxLed4.setChecked(true); try { for (int i = 0; i < 4; i++) { ledCtl.invoke(proxy, i, 1); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } else { button.setText("ALL ON"); checkBoxLed1.setChecked(false); checkBoxLed2.setChecked(false); checkBoxLed3.setChecked(false); checkBoxLed4.setChecked(false); try { for (int i = 0; i < 4; i++) { ledCtl.invoke(proxy, i, 0); } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } public void onCheckboxClicked(View view) { // Is the view now checked? boolean checked = ((CheckBox) view).isChecked(); try { // Check which checkbox was clicked switch(view.getId()) { case R.id.LED1: if (checked) { ledCtl.invoke(proxy, 0, 1); Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show(); } else { ledCtl.invoke(proxy, 0, 0); Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show(); } break; case R.id.LED2: if (checked) { ledCtl.invoke(proxy, 1, 1); Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show(); } else { ledCtl.invoke(proxy, 1, 0); Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show(); } break; case R.id.LED3: if (checked) { ledCtl.invoke(proxy, 2, 1); Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show(); } else { ledCtl.invoke(proxy, 2, 0); Toast.makeText(getApplicationContext(), "LED3 off",Toast.LENGTH_SHORT).show(); } break; case R.id.LED4: if (checked) { ledCtl.invoke(proxy, 3, 1); Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show(); } else { ledCtl.invoke(proxy, 3, 0); Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show(); } break; } } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /* name "led" should the same as the name of addService() */ // iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led")); try { Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder ledService = (IBinder)getService.invoke(null, "led"); Method asInterface = Class.forName("android.os.ILedService$Stub").getMethod("asInterface", IBinder.class); proxy = asInterface.invoke(null, ledService); ledCtl = Class.forName("android.os.ILedService$Stub$Proxy").getMethod("ledControl", int.class, int.class); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } /* Ctrl+r and then replace all make iLedService-->iLedService */ button = (Button) findViewById(R.id.BUTTON); button.setOnClickListener(new MyButtonListener()); /* Ctrl + shift + Space to insert CheckBox to ()*/ checkBoxLed1 = (CheckBox) findViewById(R.id.LED1); checkBoxLed2 = (CheckBox) findViewById(R.id.LED2); checkBoxLed3 = (CheckBox) findViewById(R.id.LED3); checkBoxLed4 = (CheckBox) findViewById(R.id.LED4); } }
posted on 2019-04-30 00:43 Hello-World3 阅读(957) 评论(0) 编辑 收藏 举报