Android Senor Framework (二) Application

2024-04-18 10:58

本文主要是介绍Android Senor Framework (二) Application,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本节主要分析的是java层次相关的软件内容

Application开发

谷歌开发者网站 sensors 中提供了AOSP提供的sensor相关的api介绍及demo;

可以参考下相关资源:

  • 传感器
  • 动态传感器
  • 位置传感器
  • 环境传感器
  • Accelerometer Play
  • API 演示 (OS - RotationVectorDemo)

App demo 实现

public class MainActivity extends AppCompatActivity implements SensorEventListener {private SensorManager mSensorManager;private Sensor mSensorAcc, mSensorMag;private TextView tvAcc, tvMag;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = findViewById(R.id.toolbar);setSupportActionBar(toolbar);tvAcc = findViewById(R.id.tvAcc);tvMag = findViewById(R.id.tvMag);mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);//!< 通过getSystemService获得SensorManager实例对象 >! NoteBy: yujixuanmSensorAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//!< 通过SensorManager 获取sensor对象 >! NoteBy: yujixuan}@Overridepublic final void onSensorChanged(SensorEvent event) {float x = event.values[0];float y = event.values[1];float z = event.values[2];if(event.sensor == mSensorAcc)tvAcc.setText("x:" + x + "\ny:" + y + "\nz:" + z);}@Overrideprotected void onResume() {super.onResume();mSensorManager.registerListener(this, mSensorAcc, SensorManager.SENSOR_DELAY_NORMAL);}@Overrideprotected void onPause() {super.onPause();mSensorManager.unregisterListener(this);}
}

实现的步骤:

  1. 通过调用通过getSystemService获得传感器服务,实现返回的是封装了SensorService的SensorManager对象
  2. 通过SensorManager 来获得指定类型的传感器对象,用来获得传感器的数据
  3. 通过SensorManager.registerListener注册SensorEventListener监听器,监听传感器
  4. 实现对sensor上报数据内容的具体操作

运行demo

以下是在Android Studio中实际demo

SensorManager

通过上面简单的app demo可知,主要过程均是通过SensorManager来完成;

改SensorManager是通过 getSystemService获取系统name 为“sensor” service得到;

/*** Use with {@link #getSystemService(String)} to retrieve a {@link* android.hardware.SensorManager} for accessing sensors.** @see #getSystemService(String)* @see android.hardware.SensorManager*/
public static final String SENSOR_SERVICE = "sensor";

Sensor服务用户程序不能直接访问, android.hardware.SensorManager 是真正用来在java程序中操作sensor的类,它是SensorService提供服务接口的封装。

因为 Manager是应用程序直接面对的接口, Manager里维护对应的Service,应用程序不能直接访问Service;

Service是服务,被所有的应用共享的服务,并非属于某一个特定的进程,也即Sensor application与SensorService不在同一个进程内,App需要使用Sensor

service就需要进程间通信,这显然不利于很高效率的开发程序,为此由manager类操作,隐藏共享操作,把细节实现隐藏封装,app应用程序只需要通过访问被暴

露出来的api接口,所以应用中与之直接交互的是SensorManager;

SensorManager提供了各种方法来访问和列出传感器,注册和取消注册传感器事件监听器,它还提供了几个传感器常量,用于报

告传感器精确度,设置数据采集频率和校准传感器;下面是这个类的定义:

public abstract class SensorManager protected static final String TAG = "SensorManager";public static final int RAW_DATA_Z = 5;/** Standard gravity (g) on Earth. This value is equivalent to 1G */public static final float STANDARD_GRAVITY = 9.80665f;
......public SensorManager() {}protected abstract List<Sensor> getFullSensorList();protected abstract List<Sensor> getFullDynamicSensorList();@Deprecatedpublic int getSensors() {return getLegacySensorManager().getSensors();}public List<Sensor> getSensorList(int type) {// cache the returned lists the first timeList<Sensor> list;final List<Sensor> fullList = getFullSensorList();synchronized (mSensorListByType) {list = mSensorListByType.get(type);if (list == null) {if (type == Sensor.TYPE_ALL) {list = fullList;} else {list = new ArrayList<Sensor>();for (Sensor i : fullList) {if (i.getType() == type)list.add(i);}}list = Collections.unmodifiableList(list);mSensorListByType.append(type, list);}}return list;}@Deprecatedpublic boolean registerListener(SensorListener listener, int sensors) {return registerListener(listener, sensors, SENSOR_DELAY_NORMAL);}public boolean registerListener(SensorEventListener listener, Sensor sensor,int samplingPeriodUs, Handler handler) {int delay = getDelay(samplingPeriodUs);return registerListenerImpl(listener, sensor, delay, handler, 0, 0);}public void unregisterListener(SensorEventListener listener, Sensor sensor) {if (listener == null || sensor == null) {return;}unregisterListenerImpl(listener, sensor);}public boolean flush(SensorEventListener listener) {return flushImpl(listener);}
.......
}

通过上面的内容可以看出SensorManager是个抽象类,真正完成管理控制sensor的是它的子类SystemSensorManager;

SystemSensorManager继承了它 做具体的实现;

SystemSensorManager.java extends SensorManagerpublic class SystemSensorManager extends SensorManager {//TODO: disable extra logging before releaseprivate static boolean DEBUG_DYNAMIC_SENSOR = true;private static native void nativeClassInit();private static native long nativeCreate(String opPackageName);private static native boolean nativeGetSensorAtIndex(long nativeInstance,Sensor sensor, int index);private static native void nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);private static final Object sLock = new Object();@GuardedBy("sLock")private static boolean sNativeClassInited = false;@GuardedBy("sLock")private static InjectEventQueue sInjectEventQueue = null;private final ArrayList<Sensor> mFullSensorsList = new ArrayList<>();private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();private boolean mDynamicSensorListDirty = true;private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
......public SystemSensorManager(Context context, Looper mainLooper) {synchronized(sLock) {if (!sNativeClassInited) {sNativeClassInited = true;nativeClassInit();}}mMainLooper = mainLooper;mTargetSdkLevel = context.getApplicationInfo().targetSdkVersion;mContext = context;mNativeInstance = nativeCreate(context.getOpPackageName());// initialize the sensor listfor (int index = 0;;++index) {Sensor sensor = new Sensor();if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;mFullSensorsList.add(sensor);mHandleToSensor.put(sensor.getHandle(), sensor);}}
......@Overrideprotected List<Sensor> getFullSensorList() {return mFullSensorsList;
......private static abstract class BaseEventQueue {private static native long nativeInitBaseEventQueue(long nativeManager,WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,String packageName, int mode, String opPackageName);private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,int maxBatchReportLatencyUs);private static native int nativeDisableSensor(long eventQ, int handle);private static native void nativeDestroySensorEventQueue(long eventQ);private static native int nativeFlushSensor(long eventQ);private static native int nativeInjectSensorData(long eventQ, int handle,}
......}

从这个类中可以本地的native方法,如:

nativeClassInit();
nativeCreate(String opPackageName);
nativeGetSensorAtIndex(long nativeInstance,Sensor sensor, int index);
nativeGetDynamicSensors(long nativeInstance, List<Sensor> list);
nativeIsDataInjectionEnabled(long nativeInstance);

通过load到的JNI访问到libc中的native方法,有关jni 和c++ 本地方法实现后面博客介绍;

除了对本地native方法的调用,SystemSensorManager 还在其构造函数中 初始化了对应的sensor list;

        for (int index = 0;;++index) {Sensor sensor = new Sensor();if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;mFullSensorsList.add(sensor);mHandleToSensor.put(sensor.getHandle(), sensor);}

Sensor对象

从app的demo代码中可以看出,一个存在的sensor是由一个Sensor类的对象来标识的,它获取自Sensor Manager,通过给定的参数,获取一个实例sensor对象;该类提供了各种方法来确定传感器的特性。

mSensorAcc = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
public Sensor getDefaultSensor(int type) {// TODO: need to be smarter, for now, just return the 1st sensorList<Sensor> l = getSensorList(type);boolean wakeUpSensor = false;// For the following sensor types, return a wake-up sensor. These types are by default// defined as wake-up sensors. For the rest of the SDK defined sensor types return a// non_wake-up version.if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||type == Sensor.TYPE_WRIST_TILT_GESTURE) {wakeUpSensor = true;}for (Sensor sensor : l) {if (sensor.isWakeUpSensor() == wakeUpSensor) return sensor;}return null;
}

Sensor类的内容如下:

public final class Sensor {mNamemVendormVersionmHandlemTypemMaxRangemResolutionmPowermMinDelaymFifoReservedEventCountmFifoMaxEventCountmStringTypemRequiredPermissionmMaxDelaymFlagsmld
// funcSensorgetNamegetVendorgetTypegetVersiongetMaximumRangegetResolutiongetPowergetMinDelaygetFifoReservedEventCountgetFifoMaxEventCountgetStringTypegetUuidgetldgetRequiredPermissiongetHandlegetMaxDelayisWakeUpSensorisDynamicSensorisAdditionallnfoSupportedisDatalnjectionSupportedsetRangetoStringsetTypesetUuid
}

Sensor Event 处理

SensorEventListener

回到app demo中,可以看出,sensor数据的处理是override了onSensorChanged方法,它在有sensor数据上报时被回调,详细的回调过程后面的内容会做分析;暂时只关注demo中的代码实现;

通过activity的定义可知,onSensorChanged方法是来自接口SensorEventListener;

接口类interface SensorEventListener (方法都是public abstract, 变量都是public static final)

用于接收新的sensor 数据上报时回调其中的抽象方法;

code:frameworks\base\core\java\android\hardware\SensorEvent.java
public interface SensorEventListener {public void onSensorChanged(SensorEvent event); //sensor数据变化public void onAccuracyChanged(Sensor sensor, int accuracy); //精度变化
}

它处理的参数类型是SensorEvent类对象;这个类的对象表示一个SensorEvent事件,并保存诸如传感器类型、时间戳、精度等信息,还有传感器的数据。

values float数组里保存了app需要用到的数据信息;按照固定的格式去读取需要的参数即可; 具体参考android API介绍,拿到event之后,对应固定的格式,拆解出的value即是我们需要的sensor数据;

public class SensorEvent {
public final float[] values;
public Sensor sensor;
public int accuracy;
public long timestamp;
SensorEvent(int valueSize) {values = new float[valueSize];}
}

registerListener

实现一个sensor监听,是先通过SensorManager.registerListener注册SensorEventListener监听器,监听sensor,注册监听器的方法实现同样是有SensorManager对象来管理,appdemo中使用获取到的mSensorManager,以及设置指定类型获取的sensor对象 acc msensor来注册监听;

mSensorManager.registerListener(this, mSensorAcc, SensorManager.SENSOR_DELAY_NORMAL);

以下是registerListener在SystemSensorManager类中的定义:

SystemSensorManager::registerListener
protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags) {
//......// listener 是activity// - one Looper per SensorEventListener// - one Looper per SensorEventQueue//   将SensorEventListener映射到一个SensorEventQueuesynchronized (mSensorListeners) {SensorEventQueue queue = mSensorListeners.get(listener);if (queue == null) {Looper looper = (handler != null) ? handler.getLooper() : mMainLooper;final String fullClassName = listener.getClass().getEnclosingClass() != null ?listener.getClass().getEnclosingClass().getName() :listener.getClass().getName();queue = new SensorEventQueue(listener, looper, this, fullClassName);if (!queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs)) {queue.dispose();return false;}mSensorListeners.put(listener, queue);return true;} else {return queue.addSensor(sensor, delayUs, maxBatchReportLatencyUs);}}//......
}

将SensorEventListener映射到一个SensorEventQueue,如果SensorEventQueue已经存在,将该sensor(mSensorAcc)添加到queue中去,如果不存在,则创建SensorEventQueue;以下是SensorEventQueue 队列的实现:

SensorEventQueue

prj\frameworks\base\core\java\android\hardware\SystemSensorManager.java
static final class SensorEventQueue extends BaseEventQueue {private final SensorEventListener mListener;private final SparseArray<SensorEvent> mSensorsEvents = new SparseArray<SensorEvent>();public SensorEventQueue(SensorEventListener listener, Looper looper,SystemSensorManager manager, String packageName) {super(looper, manager, OPERATING_MODE_NORMAL, packageName);mListener = listener;}@Overridepublic void addSensorEvent(Sensor sensor) {SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,mManager.mTargetSdkLevel));synchronized (mSensorsEvents) {mSensorsEvents.put(sensor.getHandle(), t);}}
}// Called from native code.protected void dispatchSensorEvent(int handle, float[] values, int inAccuracy,long timestamp) {final Sensor sensor = mManager.mHandleToSensor.get(handle);if (sensor == null) {// sensor disconnectedreturn;}SensorEvent t = null;synchronized (mSensorsEvents) {t = mSensorsEvents.get(handle);}// Copy from the values array.System.arraycopy(values, 0, t.values, 0, t.values.length);t.timestamp = timestamp;t.accuracy = inAccuracy;t.sensor = sensor;// call onAccuracyChanged() only if the value changesfinal int accuracy = mSensorAccuracies.get(handle);if ((t.accuracy >= 0) && (accuracy != t.accuracy)) {mSensorAccuracies.put(handle, t.accuracy);mListener.onAccuracyChanged(t.sensor, t.accuracy);}mListener.onSensorChanged(t);}

BaseEventQueue

它继承自BaseBaseEventQueue; 以下是 BaseEventQueue的定义:

prj\frameworks\base\core\java\android\hardware\SystemSensorManager.java
private static abstract class BaseEventQueue {private static native long nativeInitBaseEventQueue(long nativeManager,WeakReference<BaseEventQueue> eventQWeak, MessageQueue msgQ,String packageName, int mode, String opPackageName);private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,int maxBatchReportLatencyUs);private static native int nativeDisableSensor(long eventQ, int handle);private static native void nativeDestroySensorEventQueue(long eventQ);private static native int nativeFlushSensor(long eventQ);private static native int nativeInjectSensorData(long eventQ, int handle,float[] values,int accuracy, long timestamp);private long nSensorEventQueue;private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();protected final SparseIntArray mSensorAccuracies = new SparseIntArray();private final CloseGuard mCloseGuard = CloseGuard.get();protected final SystemSensorManager mManager;protected static final int OPERATING_MODE_NORMAL = 0;protected static final int OPERATING_MODE_DATA_INJECTION = 1;BaseEventQueue(Looper looper, SystemSensorManager manager, int mode, String packageName) {if (packageName == null) packageName = "";nSensorEventQueue = nativeInitBaseEventQueue(manager.mNativeInstance,new WeakReference<>(this), looper.getQueue(),packageName, mode, manager.mContext.getOpPackageName());mCloseGuard.open("dispose");mManager = manager;}public boolean addSensor(Sensor sensor, int delayUs, int maxBatchReportLatencyUs) {// Check if already present.int handle = sensor.getHandle();if (mActiveSensors.get(handle)) return false;// Get ready to receive events before calling enable.mActiveSensors.put(handle, true);addSensorEvent(sensor);if (enableSensor(sensor, delayUs, maxBatchReportLatencyUs) != 0) {// Try continuous mode if batching fails.if (maxBatchReportLatencyUs == 0 ||maxBatchReportLatencyUs > 0 && enableSensor(sensor, delayUs, 0) != 0) {removeSensor(sensor, false);return false;}}return true;}@Overridepublic void addSensorEvent(Sensor sensor) {SensorEvent t = new SensorEvent(Sensor.getMaxLengthValuesArray(sensor,mManager.mTargetSdkLevel));synchronized (mSensorsEvents) {mSensorsEvents.put(sensor.getHandle(), t);}}private int enableSensor(Sensor sensor, int rateUs, int maxBatchReportLatencyUs) {if (nSensorEventQueue == 0) throw new NullPointerException();if (sensor == null) throw new NullPointerException();return nativeEnableSensor(nSensorEventQueue, sensor.getHandle(), rateUs,maxBatchReportLatencyUs);}

SensorList获取

前面SensorManager构造函数中,有提过获取sensor list的过程,它在java代码中的实现如下;

public List<Sensor> getSensorList(int type) {// cache the returned lists the first timeList<Sensor> list;final List<Sensor> fullList = getFullSensorList();synchronized (mSensorListByType) {list = mSensorListByType.get(type);if (list == null) {if (type == Sensor.TYPE_ALL) {list = fullList;} else {list = new ArrayList<Sensor>();for (Sensor i : fullList) {if (i.getType() == type)list.add(i);}}list = Collections.unmodifiableList(list);mSensorListByType.append(type, list);}}return list;}
protected List<Sensor> getFullSensorList() {return mFullSensorsList;
}

实际上是反回了mFullSensorsList 列表,实际的初始化过程是子类SystemSensorManager的构造过程中实现的,如下;

// initialize the sensor list
for (int index = 0;;++index) {Sensor sensor = new Sensor();if (!nativeGetSensorAtIndex(mNativeInstance, sensor, index)) break;mFullSensorsList.add(sensor);mHandleToSensor.put(sensor.getHandle(), sensor);
}

可以看到 每一个sensor都是通过new Sensor对象,再调用本地native方法nativeGetSensorAtIndex去做实例;

本节主要分析的是java层次相关的软件内容,nativeGetSensorAtIndex通过jni访问到C++中的sensor manager,在后续的博客汇总介绍;

这篇关于Android Senor Framework (二) Application的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/914591

相关文章

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Spring Framework系统框架

序号表示的是学习顺序 IoC(控制反转)/DI(依赖注入): ioc:思想上是控制反转,spring提供了一个容器,称为IOC容器,用它来充当IOC思想中的外部。 我的理解就是spring把这些对象集中管理,放在容器中,这个容器就叫Ioc这些对象统称为Bean 用对象的时候不用new,直接外部提供(bean) 当外部的对象有关系的时候,IOC给它俩绑好(DI) DI和IO

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR

Android逆向(反调,脱壳,过ssl证书脚本)

文章目录 总结 基础Android基础工具 定位关键代码页面activity定位数据包参数定位堆栈追踪 编写反调脱壳好用的脚本过ssl证书校验抓包反调的脚本打印堆栈bilibili反调的脚本 总结 暑假做了两个月的Android逆向,记录一下自己学到的东西。对于app渗透有了一些思路。 这两个月主要做的是代码分析,对于分析完后的持久化等没有学习。主要是如何反编译源码,如何找到