在framework层满足条件时发广播,app层接收广播并调用jni层读取/proc/meminfo文件
1>framework层
先来大概介绍下android的几个层,从下到上依次是:kernel,hal,jni,framework,app
Java应用程序通过JNI(java native interface)来调用硬件抽象层接口
framework用来提供app的一些service,层位于源码的/framework/下
下面我们来实现在framework层发广播,包括判断发广播条件,以及确定接收广播对象
①先来找到framework下一个比教简单的service文件进行修改,
自己新建也可以,但是修改别人的肯定更简单些
少去了添加编译信息及mk文件等步骤,找到合适的service文件添加内容即可
这里我找到了/frameworks/base/services/appwidget/java/com/android/server/appwidget/AppWidgetService.java文件
先来导入一些包
import android.content.Context;
import com.android.server.AppWidgetBackupBridge;
import com.android.server.SystemService;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
private Context context;
private SensorManager sensorManager;
private Sensor sensor;
②来获取重力传感器
这几步分别是,
获取sensormanager,
通过sensormanager获取加速度传感器即重力传感器
通过new出自己定义的myGsensorListener类,设置sensor的监听,SensorManager.SENSOR_DELAY_GAME参数是设置刷新速度使sensor适应当前game
private void setSernorHandle() {
System.out.println("--------start ShandeActivity-------");
sensorManager=(SensorManager)context.getSystemService(context.SENSOR_SERVICE);
sensor= sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
sensorManager.registerListener(new myGsensorListener(), sensor,SensorManager.SENSOR_DELAY_GAME);
}
③判断发广播条件及发广播
下面来实现myGsensorListener类,他是继承于sensorEventListener的
onAccuracyChanged方法虽然用不到,但是由于是继承父类,必须要有
Intent intent=new Intent("android.jessie.action");是设置接收boradcast的intent对象,
其中的android.jessie.action是在app的manifest的reciver中定义的,
context.sendBroadcast(intent);是发广播
class myGsensorListener implements SensorEventListener
{
@Override
public void onSensorChanged(SensorEvent event) {
int sensorType = event.sensor.getType();
//values[0]:X轴,values[1]:Y轴,values[2]:Z轴
float[] values = event.values;
if (sensorType == Sensor.TYPE_ACCELEROMETER)
{
if ((Math.abs(values[0]) > 17 || Math.abs(values[1]) > 17 || Math
.abs(values[2]) > 17))
{
Log.d("sensor x ", "============ values[0] = " + values[0]);
Log.d("sensor y ", "============ values[1] = " + values[1]);
Log.d("sensor z ", "============ values[2] = " + values[2]);
//Toast.makeText(getApplicationContext(), "Sensor Change Event", Toast.LENGTH_SHORT).show();
Intent intent=new Intent("android.jessie.action");
context.sendBroadcast(intent);
System.out.println("--------Sensor Change Event-------");
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}
}push去
2>APP层
由于app需要调用到JNI的文件,所以需要提前配置好NDK
①Shake manifest
工程配置文件设置了app_name等属性,并设置主界面MainActivity
广播recive,reciver的name就是broadcast中的android.jessie.action,app就是通过这里来接收广播的,并调用MyReciver.java
package="com.example.shake"
android:versionCode="1"
android:versionName="1.0" >
android:minSdkVersion="19"
android:targetSdkVersion="21" />
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
android:name=".MainActivity"
android:label="@string/app_name"/>
②MyReciver.java
通过Intent intent1 = new Intent(context, MainActivity.class);指定MainActivity为目标
context.startActivity(intent1); 即在接收广播后启动主界面
package com.example.shake;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class MyReciver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Intent intent1 = new Intent(context, MainActivity.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent1);
}
}
③MainActivity.java
MyReciver.java接收到广播启动主界面后调用MainActivity.java
textView=(TextView)findViewById(R.id.tv_test1);是设置文本显示内容,内容id是id.tv_test1
然后调用NativeReadMem类的readMem方法来设置显示内容
package com.example.shake;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class MainActivity extends Activity {
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView=(TextView)findViewById(R.id.tv_test1);
System.out.println("Read meminfo:-"+NativeReadMem.readMem());
textView.setText(NativeReadMem.readMem());
}
}
ps: activity_main.xml
中定义了id.tv_test1的属性
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="match_parent"
>
android:layout_height="wrap_content"
>
android:id="@+id/tv_test1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
④
NativeReadMem.java
这便是java调用jni的接口类
System.loadLibrary("ReadmemInfo");引入ReadmemInfo模块
package com.example.shake;
public class NativeReadMem {
public native static String readMem() ;
static{
System.loadLibrary("ReadmemInfo");
}
}
⑤ReadmemInfo
通过上述命令在app工作目录生成jni文件夹以及对应的.h文件
step1.com_example_shake_NativeReadMem.h
/* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_example_shake_NativeReadMem */
#ifndef _Included_com_example_shake_NativeReadMem
#define _Included_com_example_shake_NativeReadMem
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_shake_NativeReadMem
* Method: readMem
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_shake_NativeReadMem_readMem
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
step2. com_example_shake_NativeReadMem.c
去读取/proc/meminfo文件并返回读取内容
#include "com_example_shake_NativeReadMem.h"
#include
#include
#include
#include
JNIEXPORT jstring JNICALL Java_com_example_shake_NativeReadMem_readMem
(JNIEnv *env, jclass obj){
FILE *pFile=fopen("/proc/meminfo","r"); //获取文件的指针
char pBuf[2048]={0}; //定义文件指针
char * tempbuf;
int len=0;
tempbuf=(char *)malloc(101);
if(pFile!=(FILE*)NULL)
{
while(!feof(pFile)){
fgets(tempbuf,100,pFile);
strcpy(pBuf+len,tempbuf);
len=len+strlen(tempbuf);
}
}
free(tempbuf);
fclose(pFile);
return (*env)->NewStringUTF(env, pBuf);
}
step3. Android.mk
其中的LOCAL_MODULE := ReadmemInfo就是NativeReadMem.java中所引入的库名
NativeReadMem.java也就是通过ReadmemInfo来调用jni模块的
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ReadmemInfo
LOCAL_SRC_FILES := com_example_shake_NativeReadMem.c
include $(BUILD_SHARED_LIBRARY)
大功告成~~
结果是摇动就会跳出app界面,显示/proc/meminfo内容
效果图