简单的手电筒程序(基于系统驱动节点)

上一篇文章 简单的手电筒程序(基于Camera类实现) 介绍了通过Camera类进行Flash操作,但是通过camera接口可能会有下面两个问题: 1. 因为是间接使用camera接口,所以时间上会有延时 ;2. 进行Camera相关操作,耗电会比较大。下面我们介绍另外一种方法,通过操作驱动节点进行操作,控制闪关灯亮灭。

我使用的手机是三星G5309W,节点文件为/sys/class/camera/flash/rear_flash,操作如下表:

Flash On写入 “1”
Flash Off写入 “0”

我估计并不是每个手机都适用,可以用adb命令 “echo "1" >/sys/class/camera/flash/rear_flash ”验证下你的手机是否支持,当然,前提是root的,因为是system节点,节点的权限如下


如果你发现你的手机支持上面的节点,哈哈,很高兴和可以和你继续share这个有趣的应用,如果没有这个节点,也不用桑心,下面涉及JNI操作,如果你对这个知识点有兴趣也是有所裨益。

大概的思路 : JAVA层通过JNI调用Native层函数进行节点操作

1. Java层的代码比较简单,主要是声明以及调用native函数

package com.saberhao.bulbjni;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.view.Menu;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.ToggleButton;
import android.widget.CompoundButton.OnCheckedChangeListener;

public class BulbSwitch extends Activity {
	
	ToggleButton tb;
	
	static {
	    // load the JNI so
	    System.loadLibrary("BulbJNI");  
	    }
	
	//declare the JNI function.plz pay attention to the key word -- "native"
	public native void TurnOn();
	public native void TurnOff();

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_bulb_switch);

		tb = (ToggleButton)findViewById(R.id.BulbButton);
		tb.setOnCheckedChangeListener
        (
	           new OnCheckedChangeListener()
	           {
					@Override
					public void onCheckedChanged(CompoundButton buttonView,boolean isChecked)
					{
						setBulbState(isChecked);
					}
	           }
          ); 
	}

	protected void setBulbState(boolean isChecked) {
		// TODO Auto-generated method stub  
    	ImageView iv=(ImageView)findViewById(R.id.ImageView);
		iv.setImageResource((isChecked)?R.drawable.bulb_on:R.drawable.bulb_off);
		if(isChecked)
			TurnOn();
		else
			TurnOff();
		ToggleButton tb=(ToggleButton)findViewById(R.id.BulbButton);        
		tb.setChecked(isChecked);
	}

	  private void releaseImageViews() {
		ImageView iv=(ImageView)findViewById(R.id.ImageView);
	    releaseImageView(iv);
	  }

	  private void releaseImageView(ImageView imageView) {
	    Drawable d = imageView.getDrawable();
	    if (d != null)
	      d.setCallback(null);
	    imageView.setImageDrawable(null);
	    imageView.setBackgroundDrawable(null);
	  }
}

2. 生成native h头文件

a .通过命令行进入工程目录(D:\workspace\BulbJNI)

b. 输入如下命令编译h头文件
javah -classpath bin /classes -d jni com.saberhao.bulbjni.BulbSwitch

-classpath ——类路径 bin/classes
-d ——保存目录:jni
com.android.jni.JniTest:包名+类名

通过上面步骤就可以在JNI文件夹下得到Native定义头文件 : com_saberhao_bulbjni_BulbSwitch.h
#include <jni.h>
/* Header for class com_saberhao_bulbjni_BulbSwitch */

#ifndef _Included_com_saberhao_bulbjni_BulbSwitch
#define _Included_com_saberhao_bulbjni_BulbSwitch
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL Java_com_saberhao_bulbjni_BulbSwitch_TurnOn
  (JNIEnv *, jobject);
JNIEXPORT void JNICALL Java_com_saberhao_bulbjni_BulbSwitch_TurnOff
  (JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif

当然,也可以通过NDK生成头文件,详情请参考文末的参考文献

3.编写Native处理函数

在JNI目录下新建一个Cpp文件,用于实现Native函数,这个也是本应用最重要的一步

#include<jni.h>
#include<stdio.h>
#include <fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include"com_saberhao_bulbjni_BulbSwitch.h"
#include <android/log.h>
#include <unistd.h>

#define LOG_TAG "BulbJNI"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)


#define TRUNON "1"
#define TRUNOFF "0"

FILE *fp;
int fd;
int fd0;

JNIEXPORT void JNICALL Java_com_saberhao_bulbjni_BulbSwitch_TurnOn
  (JNIEnv *, jobject)
  {
		fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);
		if(fd < 0)
		{
			LOGE("[turn on]open device error ");
		}else{
			LOGI("turn on the flash");
			write(fd,TRUNON,sizeof(TRUNON));
		}
		close(fd);
		if(fd0 < 0)
		{
			LOGE("[turn on]open test0 device error ");
		}else{
			//rewind(fp);
			LOGI("turn on test0 the flash");
			write(fd0,TRUNON,sizeof(TRUNON));
		}
		close(fd0);
  	}

JNIEXPORT void JNICALL Java_com_saberhao_bulbjni_BulbSwitch_TurnOff
  (JNIEnv *, jobject)
  {
	fd=open("/sys/class/camera/flash/rear_flash",O_WRONLY);
			if(fd < 0)
			{
				LOGE("[turn off]open device error ");
			}else{
				LOGI("turn off the flash");
				write(fd,TRUNOFF,sizeof(TRUNOFF));
			}
			close(fd);
  	}
这部分代码主要实现对节点的操作,也是本应用的核心,有一点是需要注意的,上文提到sys节点的权限,对同个所有者或者同个group是可写的,其他不赋予权限,所以在定义句柄fd的时候必须使用O_WRONLY(只写),而不能使用到 O_RDWR(可读可写),要不然会出现fd初始化失败的情况,这个问题也纠结了我很久~

4.编写JNI mk文件

native函数提供实现方法,需要编译成so文件,才能被JAVA层调用,在JNI文件夹下创建Android.mk

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := eng

LOCAL_C_INCLUDES := \$(JNI_H_INCLUDE)

LOCAL_PRELINK_MODULE := false

LOCAL_LDLIBS := -llog -lGLESv2
LOCAL_MODULE := libBulbJNI
LOCAL_SRC_FILES :=BulbJNI.cpp

include $(BUILD_SHARED_LIBRARY)


LOCAL_LDLIBS := -llog -lGLESv2         //在Native函数中打log必须添加的lib

LOCAL_MODULE_TAGS := eng           //在Eng模式下编译

LOCAL_SRC_FILES -编译的源文件

LOCAL_MODULE -编译的目标对象


5. 编译生成so文件

a. 配置NDK

打开Eclipse,点Window->Preferences->Android->NDK,设置NDK路径,例如D:\android-ndk-r9d-windows-x86\android-ndk-r9d

b. 点Properties->C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd

c. 在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录

全部编译之后,就可以再libs目录下看到对应的so文件


6. 添加app mk文件

由于节点 /sys/class/camera/flash/rear_flash 为系统节点,普通应用无法直接操作,需要在xml中添加

android:sharedUserId="android.uid.system"

同时需要在 app的android.mk中添加

LOCAL_CERTIFICATE := platform 

才能进行操作,但是eclipse中无法添加Android.mk,所以必须在源代码环境中编译生成apk,添加的mk如下

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := eng
LOCAL_DEX_PREOPT := false
LOCAL_PRIVILEGED_MODULE := true
LOCAL_PACKAGE_NAME := BulbJNI
LOCAL_CERTIFICATE := platform

LOCAL_SRC_FILES := $(call all-subdir-java-files)

include $(BUILD_PACKAGE)

##################################################
# Use the folloing include to make our test apk.
include $(call all-makefiles-under,$(LOCAL_PATH))
最后,在源码中使用mm进行部分编译即可生成apk

运行效果如下:

Flash OnFlash Off

源代码,请点击 这里下载,稍后会传到github~


相关参考文档:

http://jingyan.baidu.com/article/5d6edee22d908799eadeec9f.html

http://blog.csdn.net/sdvch/article/details/17492861

http://blog.csdn.net/vincent_czz/article/details/7199567

http://jingyan.baidu.com/article/5d6edee22d908799eadeec9f.html


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值