Android传感器开发与智能设备案例实战
上QQ阅读APP看书,第一时间看更新

第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,测量应用于设备xyz轴上的加速度,又叫作G-sensor。

(2)TYPE_AMBIENT_TEMPERATURE:温度传感器,单位是℃,能够测量并返回当前的温度。

(3)TYPE_GRAVITY:重力传感器,单位是m/s2,用于测量设备xyz轴上的重力,也叫作GV-sensor,地球上的数值是9.8 m/s2

(4)TYPE_GYROSCOPE:陀螺仪传感器,单位是rad/s2,能够测量设备xyz三轴的角加速度数据。

(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 执行效果