第6章 Android传感器系统概览
在Android系统中提供的主要传感器有加速度、磁场、方向、陀螺仪、光线、压力、温度和接近等传感器。传感器系统会主动对上层报告传感器精度和数据的变化,并且提供了设置传感器精度的接口,这些接口可以在Java应用和Java框架中使用。本章将详细讲解在Android系统中使用传感器技术开发智能设备应用程序的基本流程,为读者步入本书后面知识的学习打下坚实的基础。
6.1 Android设备的传感器系统
本书在前面第5章中,已经详细讲解了Android传感器系统的基本架构。本节将详细讲解调用传感器API接口,在Android智能设备中开发应用程序的方法。
6.1.1 包含的传感器
在安装Android SDK后,依次打开安装目录中下面的帮助文件。
android SDK/sdk/docs/reference/android/hardware/Sensor.html
在此文件中列出了Android传感器系统所包含的所有传感器类型,如图6-1所示。
▲图6-1 Android传感器系统的类型
另外,也可以直接在线登录http://developer.android.com/reference/android/hardware/Sensor.html来查看。由此可见,在当前最新(作者写稿时最新)版本Android 4.4中一共提供了18种传感器API接口。各个类型的具体说明如下所示。
(1)TYPE_ACCELEROMETER:加速度传感器,单位是m/s2,测量应用于设备x、y、z轴上的加速度,又叫作G-sensor。
(2)TYPE_AMBIENT_TEMPERATURE:温度传感器,单位是℃,能够测量并返回当前的温度。
(3)TYPE_GRAVITY:重力传感器,单位是m/s2,用于测量设备x、y、z轴上的重力,也叫作GV-sensor,地球上的数值是9.8 m/s2。
(4)TYPE_GYROSCOPE:陀螺仪传感器,单位是rad/s2,能够测量设备x、y、z三轴的角加速度数据。
(5)TYPE_LIGHT:光线感应传感器,单位是lx,能够检测周围的光线强度,在手机系统中主要用于调节LCD亮度。
(6)TYPE_LINEAR_ACCELERATION:线性加速度传感器,单位是m/s2,能够获取加速度传感器去除重力的影响得到的数据。
(7)TYPE_MAGNETIC_FIELD:磁场传感器,单位是μT(微特斯拉),能够测量设备周围3个物理轴(x, y, z)的磁场。
(8)TYPE_ORIENTATION:方向传感器,用于测量设备围绕3个物理轴(x, y, z)的旋转角度,在新版本中已经使用SensorManager.getOrientation()替代。
(9)TYPE_PRESSURE:气压传感器,单位是hPa(百帕斯卡),能够返回当前环境下的压强。
(10)TYPE_PROXIMITY:距离传感器,单位是cm,能够测量某个对象到屏幕的距离。可以在打电话时判断人耳到电话屏幕距离,以关闭屏幕而达到省电功能。
(11)TYPE_RELATIVE_HUMIDITY:湿度传感器,能够测量周围环境的相对湿度。
(12)TYPE_ROTATION_VECTOR:旋转向量传感器,旋转矢量代表设备的方向,是一个将坐标轴和角度混合计算得到的数据。
(13)TYPE_TEMPERATURE:温度传感器,在新版本中被TYPE_AMBIENT_TEMPERATURE替换。
(14)TYPE_ALL:返回所有的传感器类型。
(15)TYPE_GAME_ROTATION_VECTOR:除了不能使用地磁场之外,和TYPE_ROTATION_VECTOR的功能完全相同。
(16)TYPE_GYROSCOPE_UNCALIBRATED:提供了能够让应用调整传感器的原始值,定义了一个描述未校准陀螺仪的传感器类型。
(17)TYPE_MAGNETIC_FIELD_UNCALIBRATED:和TYPE_GYROSCOPE_UNCALIBRATED相似,也提供了能够让应用调整传感器的原始值,定义了一个描述未校准陀螺仪的传感器类型。
(18)TYPE_SIGNIFICANT_MOTION:运动触发传感器,应用程序不需要为这种传感器触发任何唤醒锁。能够检测当前设备是否运动,并发送检测结果。
6.1.2 检测当前设备支持的传感器
在接下来的实例中,将演示在Android设备中检测当前设备支持传感器类型的方法。本实例的功能是检测当前设备支持的传感器类型,具体实现流程如下所示。
布局文件main.xml的具体实现代码如下所示。
<linearlayout android:layout_height="fill_parent" android:layout_width="fill_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <textview android:layout_height="wrap_content" android:layout_width="fill_parent" android:text="" android:id="@+id/TextView01" > </textview> </linearlayout>
主程序文件MainActivity.java的具体实现代码如下所示。
public class MainActivity extends Activity { /** Called when the activity is first created. */ @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //准备显示信息的UI组建 final TextView tx1 = (TextView) findViewById(R.id.TextView01); //从系统服务中获得传感器管理器 SensorManager sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE); //从传感器管理器中获得全部的传感器列表 List<Sensor> allSensors = sm.getSensorList(Sensor.TYPE_ALL); //显示有多少个传感器 tx1.setText("经检测该手机有" + allSensors.size() + "个传感器,它们分别是:\n"); //显示每个传感器的具体信息 for (Sensor s : allSensors) { String tempString = "\n" + " 设备名称:" + s.getName() + "\n" + " 设 备版本:"+s.getVersion()+"\n"+" 供应商:"+s.getVendor()+"\n"; switch (s.getType()) { case Sensor.TYPE_ACCELEROMETER: tx1.setText(tx1.getText().toString() + s.getType() + " 加速 度传感器accelerometer" + tempString); break; case Sensor.TYPE_GYROSCOPE: tx1.setText(tx1.getText().toString() + s.getType() + " 陀螺 仪传感器gyroscope" + tempString); break; case Sensor.TYPE_LIGHT: tx1.setText(tx1.getText().toString() + s.getType() + " 光线 感应传感器light" + tempString); break; case Sensor.TYPE_MAGNETIC_FIELD: tx1.setText(tx1.getText().toString() + s.getType() + " 电磁 场传感器magnetic field" + tempString); break; case Sensor.TYPE_ORIENTATION: tx1.setText(tx1.getText().toString() + s.getType() + " 方向 传感器orientation" + tempString); break; case Sensor.TYPE_PRESSURE: tx1.setText(tx1.getText().toString() + s.getType() + " 压力 传感器pressure" + tempString); break; case Sensor.TYPE_PROXIMITY: tx1.setText(tx1.getText().toString() + s.getType() + " 距离 传感器proximity" + tempString); break; case Sensor.TYPE_AMBIENT_TEMPERATURE : tx1.setText(tx1.getText().toString() + s.getType() + " 温度 传感器temperature" + tempString); break; default: tx1.setText(tx1.getText().toString() + s.getType() + " 未知 传感器" + tempString); break; } } } }
上述实例代码需要在真机中运行,执行后将会列表显示当前设备所支持的传感器类型。如图6-2所示。
▲图6-2 执行效果
6.2 使用SensorSimulator
在进行和传感器相关的开发工作时,使用SensorSimulator可以提高开发效率。SensorSimulator是一个开源免费的传感器小型工具,通过该工具可以在模拟器中调试传感器的应用。搭建SensorSimulator开发环境的基本流程如下所示。
(1)下载SensorSimulator,读者可从http://code.google.com/p/openintents/wiki/SensorSimulator网站找到该工具的下载链接。这里下载的是sensorsimulator-1.1.1.zip版本,如图6-3所示。
▲图6-3 下载sensorsimulator-1.1.1.zip
(2)将下载好的SensorSimulator解压到本地根目录,例如C盘的根目录。
(3)向模拟器安装SensorSimulatorSettings-1.1.1.apk。首先在操作系统中依次选择“开始”|“运行”,进入“运行”对话框。
(4)在“运行”对话框输入“cmd”进入cmd命令行,之后通过cd命令将当前目录导航到SensorSimulatorSettings-1.1.1.apk目录下,然后输入下列命令向模拟器安装该apk。
adb install SensorSimulatorSettings-1.1.1.apk
如图6-4所示。在此需要注意的是,安装apk时,一定要保证模拟器正在运行才可以,安装成功后会输出“Success”提示。
▲图6-4 安装apk
接下来开始配置应用程序,假设要在项目“jiaSCH”中使用SensorSimulator,则配置流程如下所示。
(1)在Eclipse中打开项目“jiaSCH”,然后为该项目添加JAR包,使其能够使用SensorSimulator工具的类和方法。添加方法非常简单,在Eclipse的Package Explorer中找到该项目的文件夹“jiaSCH”,然后右键单击该文件夹并选择“Properties”选项,弹出图6-5所示的“Properties for jiaS”窗口。
▲图6-5 “Properties for jiaS”窗口
(2)选择左面的“Java Build Path”选项,然后单击“Libraries”选项卡,如图6-6所示。
▲图6-6 “Libraries”选项卡
(3)单击“Add External JARs”按钮,在弹出的“JAR Selection”对话框中找到Sensorsimulator安装目录下的sensorsimulator-lib-1.1.1.jar,并将其添加到该项目中,如图6-7所示。
▲图6-7 添加需要的JAR包
(4)开始启动sensorsimulator.jar,并对手机模拟器上的SensorSimulator进行必要的配置。首先在“C:\sensorsimulator-1.1.1\bin”目录下找到sensorsimulator.jar并启动,运行后的界面如图6-8所示。
▲图6-8 传感器的模拟器
(5)接下来开始进行手机模拟器和SensorSimulator的连接配置工作,运行手机模拟器上安装好的SensorSimulatorSettings.apk,如图6-9所示。
▲图6-9 运行手机模拟器上的SensorSimulatorSettings-1.1.1.apk
(6)在图6-9中输入SensorSimulator启动时显示的IP地址和端口号,单击屏幕右上角的“Testing”按钮后转到测试连接界面。如图6-10所示。
▲图6-10 测试连接界面
(7)单击屏幕上的“Connect”按钮进入下一界面,如图6-11所示。在此界面中可以选择需要监听的传感器,如果能够从传感器中读取到数据,说明SensorSimulator与手机模拟器连接成功,就可以测试自己开发的应用程序了。
▲图6-11 连接界面
到此为止,使用Eclipse结合SensorSimulator配置传感器应用程序的基本流程介绍完毕。
6.3 查看传感器的相关信息
在接下来的实例中,将演示在Android智能设备中查看传感器数据的方法。
本实例的功能是查看设备中传感器的基本信息,本实例源码来源于:
https://github.com/gast-lib/gast-lib
读者可以自行登录下载。本实例的具体实现流程如下所示。
(1)编写用户交互界面SensorListActivity,实现了两个用户界面交互。其中主界面sensor_main.xml用于列表显示系统中的传感器,功能和前面的实例6-1类似。文件sensor_main.xml的主要实现代码如下所示。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" > <fragment android:id="@+id/frag_sensor_select" android:layout_width="fill_parent" android:layout_height="fill_parent" class="root.gast.playground.sensor.SensorSelectorFragment" /> <fragment android:id="@+id/frag_sensor_view" android:layout_width="fill_parent" android:layout_height="fill_parent" class="root.gast.playground.sensor.SensorDisplayFragment" /> </LinearLayout>
文件SensorListActivity.java的具体实现代码如下所示。
public class SensorListActivity extends FragmentActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sensor_main); // wire up the fragments so selector // can call display SensorDisplayFragment sensorDisplay = (SensorDisplayFragment) getSupportFragmentManager() .findFragmentById(R.id.frag_sensor_view); SensorSelectorFragment sensorSelect = (SensorSelectorFragment) getSupportFragmentManager() .findFragmentById(R.id.frag_sensor_select); sensorSelect.setSensorDisplay(sensorDisplay); } }
通过上述代码可知,传感器类型列表显示功能是通过调用文件SensorSelectorFragment.java实现的,具体实现代码如下所示。
public class SensorSelectorFragment extends ListFragment { private static final String TAG = "SensorSelectorFragment"; private SensorDisplayFragment sensorDisplay; /** * connect with a display fragment to call later when user clicks a sensor * name, also setup the ListAdapter to show all the Sensors */ public void setSensorDisplay(SensorDisplayFragment sensorDisplay) { this.sensorDisplay = sensorDisplay; SensorManager sensorManager = (SensorManager) getActivity().getSystemService( Activity.SENSOR_SERVICE); List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL); this.setListAdapter(new SensorListAdapter(getActivity() .getApplicationContext(), android.R.layout.simple_list_item_1, sensors)); } /** * hide the list of sensors and show the sensor display fragment * add these changes to the backstack */ private void showSensorFragment(Sensor sensor) { sensorDisplay.displaySensor(sensor); FragmentTransaction ft = getActivity().getSupportFragmentManager().beginTransaction(); ft.hide(this); ft.show(sensorDisplay); ft.addToBackStack("Showing sensor: " + sensor.getName()); ft.commit(); } /** * list view adapter to show sensor names and respond to clicks. */ private class SensorListAdapter extends ArrayAdapter<Sensor> { public SensorListAdapter(Context context, int textViewResourceId, List<Sensor> sensors) { super(context, textViewResourceId, sensors); } /** * create a text view containing the sensor name */ @Override public View getView(final int position, View convertView, ViewGroup parent) { final Sensor selectedSensor = getItem(position); if (convertView == null) { convertView = LayoutInflater.from(getContext()).inflate( android.R.layout.simple_list_item_1, null); } ((TextView) convertView).setText(selectedSensor.getName()); convertView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (BuildConfig.DEBUG) { Log.d(TAG, "display sensor! " + selectedSensor.getName()); } showSensorFragment(selectedSensor); } }); return convertView; } } }
(2)再看第2个界面,当用户在主界面选择列表中的某一个传感器时,会显示这个传感器的详细信息。界面文件sensors_north_main.xml的主要实现代码如下所示。
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <RadioGroup android:id="@+id/sensorRateSelector" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" > <RadioButton android:id="@+id/delayFastest" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_FASTEST" android:checked="false"/> <RadioButton android:id="@+id/delayGame" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_GAME" android:checked="false"/> <RadioButton android:id="@+id/delayNormal" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_NORMAL" android:checked="true"/> <RadioButton android:id="@+id/delayUi" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="SENSOR_DELAY_UI" android:checked="false"/> </RadioGroup> <View android:id="@+id/seperator" style="@style/line_separator" android:layout_below="@id/sensorRateSelector" /> <TextView android:id="@+id/nameLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/seperator" android:layout_alignParentLeft="true" android:text="Name:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/nameLabel" android:layout_alignTop="@id/nameLabel" android:layout_alignBottom="@id/nameLabel" /> <TextView android:id="@+id/typeLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/nameLabel" android:layout_below="@id/nameLabel" android:text="Type:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/type" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/typeLabel" android:layout_alignTop="@id/typeLabel" android:layout_alignBottom="@id/typeLabel"/> <TextView android:id="@+id/maxRangeLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/nameLabel" android:layout_below="@id/typeLabel" android:text="Max Range:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/maxRange" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/maxRangeLabel" android:layout_alignTop="@id/maxRangeLabel" android:layout_alignBottom="@id/maxRangeLabel"/> <TextView android:id="@+id/minDelayLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/maxRangeLabel" android:layout_below="@id/maxRangeLabel" android:text="Min Delay:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/minDelay" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/minDelayLabel" android:layout_alignTop="@id/minDelayLabel" android:layout_alignBottom="@id/minDelayLabel"/> <TextView android:id="@+id/powerLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/minDelayLabel" android:layout_below="@id/minDelayLabel" android:text="Power:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/power" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/powerLabel" android:layout_alignTop="@id/powerLabel" android:layout_alignBottom="@id/powerLabel" android:layout_marginRight="5dip"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/power" android:layout_alignTop="@id/power" android:layout_alignBottom="@id/power" android:text="mA"/> <TextView android:id="@+id/resolutionLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/powerLabel" android:layout_below="@id/powerLabel" android:text="Resolution:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/resolution" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/resolutionLabel" android:layout_alignTop="@id/resolutionLabel" android:layout_alignBottom="@id/resolutionLabel"/> <TextView android:id="@+id/vendorLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/resolutionLabel" android:layout_below="@id/resolutionLabel" android:text="Vendor:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/vendor" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/vendorLabel" android:layout_alignTop="@id/vendorLabel" android:layout_alignBottom="@id/vendorLabel"/> <TextView android:id="@+id/versionLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/versionLabel" android:layout_alignLeft="@id/vendorLabel" android:layout_below="@id/vendorLabel" android:text="Version:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/version" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/versionLabel" android:layout_alignTop="@id/versionLabel" android:layout_alignBottom="@id/versionLabel"/> <TextView android:id="@+id/accuracyLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/versionLabel" android:layout_below="@id/versionLabel" android:text="Accuracy:" android:layout_marginRight="5dip" /> <TextView android:id="@+id/accuracy" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/accuracyLabel" android:layout_alignTop="@id/accuracyLabel" android:layout_alignBottom="@id/accuracyLabel"/> <! -- timestamp --> <TextView android:id="@+id/timestampLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/accuracyLabel" android:layout_below="@id/accuracyLabel" android:layout_marginRight="5dip" android:text="Timestamp:" /> <TextView android:id="@+id/timestamp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/timestampLabel" android:layout_alignTop="@id/timestampLabel" android:layout_alignBottom="@id/timestampLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <TextView android:id="@+id/timestampUnits" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/timestamp" android:layout_alignTop="@id/timestamp" android:layout_alignBottom="@id/timestamp" android:visibility="gone" android:text="(ns)" /> <TextView android:id="@+id/dataLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/accuracyLabel" android:layout_below="@id/timestampLabel" android:layout_marginRight="5dip" android:visibility="gone"/> <TextView android:id="@+id/dataUnits" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/dataLabel" android:layout_alignTop="@id/dataLabel" android:layout_alignBottom="@id/dataLabel" android:visibility="gone" /> <TextView android:id="@+id/singleValue" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/dataUnits" android:layout_alignTop="@id/dataUnits" android:layout_alignBottom="@id/dataUnits" android:visibility="gone" /> <! -- X axis --> <TextView android:id="@+id/xAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/dataLabel" android:layout_below="@id/dataLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/xAxisLabel" /> <TextView android:id="@+id/xAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/xAxisLabel" android:layout_alignTop="@id/xAxisLabel" android:layout_alignBottom="@id/xAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- Y axis --> <TextView android:id="@+id/yAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/xAxisLabel" android:layout_below="@id/xAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/yAxisLabel" /> <TextView android:id="@+id/yAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/yAxisLabel" android:layout_alignTop="@id/yAxisLabel" android:layout_alignBottom="@id/yAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- Z axis --> <TextView android:id="@+id/zAxisLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/yAxisLabel" android:layout_below="@id/yAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="@string/zAxisLabel" /> <TextView android:id="@+id/zAxis" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/zAxisLabel" android:layout_alignTop="@id/zAxisLabel" android:layout_alignBottom="@id/zAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" /> <! -- cos value (for rotation vector only) --> <TextView android:id="@+id/cosLabel" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignLeft="@id/zAxisLabel" android:layout_below="@id/zAxisLabel" android:layout_marginRight="5dip" android:visibility="gone" android:text="cos(\u0398/2):" /> <TextView android:id="@+id/cos" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/cosLabel" android:layout_alignTop="@id/cosLabel" android:layout_alignBottom="@id/cosLabel" android:layout_marginRight="5dip" android:visibility="gone" /> </RelativeLayout>
某个传感器的详细信息功能是通过文件SensorDisplayFragment.java实现的,主要代码如下所示。
public class SensorDisplayFragment extends Fragment implements SensorEventListener { private static final String TAG = "SensorDisplayFragment"; private static final String THETA = "\u0398"; private static final String ACCELERATION_UNITS = "m/s\u00B2"; private SensorManager sensorManager; private Sensor sensor; private TextView name; private TextView type; private TextView maxRange; private TextView minDelay; private TextView power; private TextView resolution; private TextView vendor; private TextView version; private TextView accuracy; private TextView timestampLabel; private TextView timestamp; private TextView timestampUnits; private TextView dataLabel; private TextView dataUnits; private TextView xAxis; private TextView xAxisLabel; private TextView yAxis; private TextView yAxisLabel; private TextView zAxis; private TextView zAxisLabel; private TextView singleValue; private TextView cosLabel; private TextView cos; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.sensor_view, null); sensorManager = (SensorManager) getActivity().getSystemService(Context.SENSOR_SERVICE); name = (TextView) layout.findViewById(R.id.name); type = (TextView) layout.findViewById(R.id.type); maxRange = (TextView) layout.findViewById(R.id.maxRange); minDelay = (TextView) layout.findViewById(R.id.minDelay); power = (TextView) layout.findViewById(R.id.power); resolution = (TextView) layout.findViewById(R.id.resolution); vendor = (TextView) layout.findViewById(R.id.vendor); version = (TextView) layout.findViewById(R.id.version); accuracy = (TextView) layout.findViewById(R.id.accuracy); timestampLabel = (TextView) layout.findViewById(R.id.timestampLabel); timestamp = (TextView) layout.findViewById(R.id.timestamp); timestampUnits = (TextView) layout.findViewById(R.id.timestampUnits); dataLabel = (TextView) layout.findViewById(R.id.dataLabel); dataUnits = (TextView) layout.findViewById(R.id.dataUnits); xAxis = (TextView) layout.findViewById(R.id.xAxis); xAxisLabel = (TextView) layout.findViewById(R.id.xAxisLabel); yAxis = (TextView) layout.findViewById(R.id.yAxis); yAxisLabel = (TextView) layout.findViewById(R.id.yAxisLabel); zAxis = (TextView) layout.findViewById(R.id.zAxis); zAxisLabel = (TextView) layout.findViewById(R.id.zAxisLabel); singleValue = (TextView) layout.findViewById(R.id.singleValue); cosLabel = (TextView) layout.findViewById(R.id.cosLabel); cos = (TextView) layout.findViewById(R.id.cos); layout.findViewById(R.id.delayFastest).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_FASTEST); } }); layout.findViewById(R.id.delayGame).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_GAME); } }); layout.findViewById(R.id.delayNormal).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } }); layout.findViewById(R.id.delayUi).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { sensorManager.unregisterListener(SensorDisplayFragment.this); sensorManager.registerListener(SensorDisplayFragment.this, sensor, SensorManager.SENSOR_DELAY_UI); } }); return layout; } public void displaySensor(Sensor sensor) { if (BuildConfig.DEBUG) { Log.d(TAG, "display the sensor"); } this.sensor = sensor; name.setText(sensor.getName()); type.setText(String.valueOf(sensor.getType())); maxRange.setText(String.valueOf(sensor.getMaximumRange())); minDelay.setText(String.valueOf(sensor.getMinDelay())); power.setText(String.valueOf(sensor.getPower())); resolution.setText(String.valueOf(sensor.getResolution())); vendor.setText(String.valueOf(sensor.getVendor())); version.setText(String.valueOf(sensor.getVersion())); sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_NORMAL); } /** * @see android.hardware.SensorEventListener#onAccuracyChanged(android.hardware. Sensor, int) */ @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { switch(accuracy) { case SensorManager.SENSOR_STATUS_ACCURACY_HIGH: this.accuracy.setText("SENSOR_STATUS_ACCURACY_HIGH"); break; case SensorManager.SENSOR_STATUS_ACCURACY_MEDIUM: this.accuracy.setText("SENSOR_STATUS_ACCURACY_MEDIUM"); break; case SensorManager.SENSOR_STATUS_ACCURACY_LOW: this.accuracy.setText("SENSOR_STATUS_ACCURACY_LOW"); break; case SensorManager.SENSOR_STATUS_UNRELIABLE: this.accuracy.setText("SENSOR_STATUS_UNRELIABLE"); break; } } /** * @see android.hardware.SensorEventListener#onSensorChanged(android.hardware. SensorEvent) */ @Override public void onSensorChanged(SensorEvent event) { onAccuracyChanged(event.sensor, event.accuracy); timestampLabel.setVisibility(View.VISIBLE); timestamp.setVisibility(View.VISIBLE); timestamp.setText(String.valueOf(event.timestamp)); timestampUnits.setVisibility(View.VISIBLE); switch (event.sensor.getType()) { case Sensor.TYPE_ACCELEROMETER: showEventData("Acceleration - gravity on axis", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_MAGNETIC_FIELD: showEventData("Abient Magnetic Field", "uT", event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_GYROSCOPE: showEventData("Angular speed around axis", "radians/sec", event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_LIGHT: showEventData("Ambient light", "lux", event.values[0]); break; case Sensor.TYPE_PRESSURE: showEventData("Atmospheric pressure", "hPa", event.values[0]); break; case Sensor.TYPE_PROXIMITY: showEventData("Distance", "cm", event.values[0]); break; case Sensor.TYPE_GRAVITY: showEventData("Gravity", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_LINEAR_ACCELERATION: showEventData("Acceleration (not including gravity)", ACCELERATION_UNITS, event.values[0], event.values[1], event.values[2]); break; case Sensor.TYPE_ROTATION_VECTOR: showEventData("Rotation Vector", null, event.values[0], event.values[1], event.values[2]); xAxisLabel.setText("x*sin(" + THETA + "/2)"); yAxisLabel.setText("y*sin(" + THETA + "/2)"); zAxisLabel.setText("z*sin(" + THETA + "/2)"); if (event.values.length == 4) { cosLabel.setVisibility(View.VISIBLE); cos.setVisibility(View.VISIBLE); cos.setText(String.valueOf(event.values[3])); } break; case Sensor.TYPE_ORIENTATION: showEventData("Angle", "Degrees", event.values[0], event.values[1], event.values[2]); xAxisLabel.setText(R.string.azimuthLabel); yAxisLabel.setText(R.string.pitchLabel); zAxisLabel.setText(R.string.rollLabel); break; case Sensor.TYPE_RELATIVE_HUMIDITY: showEventData("Relatice ambient air humidity", "%", event.values[0]); break; case Sensor.TYPE_AMBIENT_TEMPERATURE: showEventData("Ambien temperature", "degree Celcius", event.values[0]); break; } } private void showEventData(String label, String units, float x, float y, float z) { dataLabel.setVisibility(View.VISIBLE); dataLabel.setText(label); if (units == null) { dataUnits.setVisibility(View.GONE); } else { dataUnits.setVisibility(View.VISIBLE); dataUnits.setText("(" + units + "):"); } singleValue.setVisibility(View.GONE); xAxisLabel.setVisibility(View.VISIBLE); xAxisLabel.setText(R.string.xAxisLabel); xAxis.setVisibility(View.VISIBLE); xAxis.setText(String.valueOf(x)); yAxisLabel.setVisibility(View.VISIBLE); yAxisLabel.setText(R.string.yAxisLabel); yAxis.setVisibility(View.VISIBLE); yAxis.setText(String.valueOf(y)); zAxisLabel.setVisibility(View.VISIBLE); zAxisLabel.setText(R.string.zAxisLabel); zAxis.setVisibility(View.VISIBLE); zAxis.setText(String.valueOf(z)); } private void showEventData(String label, String units, float value) { dataLabel.setVisibility(View.VISIBLE); dataLabel.setText(label); dataUnits.setVisibility(View.VISIBLE); dataUnits.setText("(" + units + "):"); singleValue.setVisibility(View.VISIBLE); singleValue.setText(String.valueOf(value)); xAxisLabel.setVisibility(View.GONE); xAxis.setVisibility(View.GONE); yAxisLabel.setVisibility(View.GONE); yAxis.setVisibility(View.GONE); zAxisLabel.setVisibility(View.GONE); zAxis.setVisibility(View.GONE); } /** * @see android.support.v4.app.Fragment#onHiddenChanged(boolean) */ @Override public void onHiddenChanged(boolean hidden) { super.onHiddenChanged(hidden); if (hidden) { if (BuildConfig.DEBUG) { Log.d(TAG, "Unregistering listener"); } sensorManager.unregisterListener(this); } } /** * @see android.support.v4.app.Fragment#onPause() */ @Override public void onPause() { super.onPause(); if (BuildConfig.DEBUG) { Log.d(TAG, "onPause"); Log.d(TAG, "Unregistering listener"); } sensorManager.unregisterListener(this); } }
到此为止,整个实例介绍完毕,执行后的效果如图6-12所示。
▲图6-12 执行效果