Help us understand the problem. What is going on with this article?

Android端末に搭載されているセンサーの一覧を取得する

More than 3 years have passed since last update.

私事ですが、Nexus7(2013)の回転センサーが効かなくなってしまいました。

ほぼ、カーナビとして固定状態で使っているので、回転しなくても困らないのですが、そういえば、この端末にはどんなセンサーが搭載されているんだろう?と疑問に思ったので、久々にAndroidの開発環境を整えて、リストにして表示するようにしてみました。

Android Studioのインストール

Download Android Studio and SDK Toolsから、ダウンロードして、インストールします。
執筆時点で、2.3.2.0というバージョンをダウンロードすることができました。

Android Studioの設定

Android Studio自体にこれといった設定はしていません。デフォルトのまま使えます。

emulatorの作成

実機デバッグする際には必要ないのですが、実機を繋ぐのはソレはソレで面倒なので、AVD ManagerでNexus7相当のemulatorを設定します。

数年前と比較して、emulatorがサクサク動く用になっていて、驚きました。

SensorListActivityの作成

"New Project"から

「File」→「New」→「New Project」で新しいプロジェクトの諸設定をします。あまり、色々考えず、とりあえず、「Empty Activity」で。

このEmpty Activityをちょっと書き換えます。

public class SensorListActivity extends AppCompatActivity

AppCompatActivityを継承しているようになっているけれど、これをListActivityの継承に変更します。

public class SensorListActivity extends ListActivity

それに合わせて、リソースファイルである、activity_sensor_list.xmlもListViewとListViewに何も表示されない時に代替の文字列を表示するTextViewを設定します。これは、ListActivityを使う時にはありがちな設定で、ちょっとしたチュートリアルにも必ず出てくると思います。

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="jp.gr.java_conf.fukuit.sensoractivity.SensorListActivity">

    <ListView android:id="@android:id/list"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scrollbars="vertical"
        android:scrollbarStyle="outsideInset"
        android:smoothScrollbar="true" />
    <TextView android:id="@android:id/empty" android:text="@string/empty_text"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />

</android.support.constraint.ConstraintLayout>

Sensor項目を取得する

Sensor項目を取得するための変数を用意します。Sensor項目を格納するための、SensorItemというクラスを定義して、取得できそうなSensorの型ごとにインスタンスを生成し、ArrayListにそれを格納します。

import java.util.ArrayList;

private ArrayList<SensorItem> sensorList;
private void initSensorList(){
    sensorList = new ArrayList<SensorItem>();
    sensorList.add( new SensorItem(Sensor.TYPE_ACCELEROMETER, "ACCELEROMETER"));
    sensorList.add( new SensorItem(Sensor.TYPE_AMBIENT_TEMPERATURE,"AMBIENT_TEMPERATURE"));
    sensorList.add( new SensorItem(Sensor.TYPE_DEVICE_PRIVATE_BASE,"DEVICE_PRIVATE_BASE"));
    sensorList.add( new SensorItem(Sensor.TYPE_GAME_ROTATION_VECTOR,"GAME_ROTATION_VECTOR"));
    sensorList.add( new SensorItem(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR,"GEOMAGNETIC_ROTATION_VECTOR"));
    sensorList.add( new SensorItem(Sensor.TYPE_GRAVITY, "GRAVITY"));
    sensorList.add( new SensorItem(Sensor.TYPE_GYROSCOPE, "GYROSCOPE"));
    sensorList.add( new SensorItem(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, "GYROSCOPE_UNCALIBRATED"));
    sensorList.add( new SensorItem(Sensor.TYPE_HEART_BEAT, "HEART_BEAT"));
    sensorList.add( new SensorItem(Sensor.TYPE_HEART_RATE, "HEART_RATE"));
    sensorList.add( new SensorItem(Sensor.TYPE_LIGHT, "LIGHT"));
    sensorList.add( new SensorItem(Sensor.TYPE_LINEAR_ACCELERATION, "LINEAR_ACCELERATION"));
    sensorList.add( new SensorItem(Sensor.TYPE_MAGNETIC_FIELD, "MAGNETIC_FIELD"));
    sensorList.add( new SensorItem(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, "MAGNETIC_FIELD_UNCALIBRATED"));
    sensorList.add( new SensorItem(Sensor.TYPE_MOTION_DETECT, "MOTION_DETECT"));
    sensorList.add( new SensorItem(Sensor.TYPE_POSE_6DOF, "POSE_6DOF"));
    sensorList.add( new SensorItem(Sensor.TYPE_PRESSURE, "PRESSURE"));
    sensorList.add( new SensorItem(Sensor.TYPE_PROXIMITY, "PROXIMITY"));
    sensorList.add( new SensorItem(Sensor.TYPE_RELATIVE_HUMIDITY, "RELATIVE_HUMIDITY"));
    sensorList.add( new SensorItem(Sensor.TYPE_ROTATION_VECTOR, "ROTATION_VECTOR"));
    sensorList.add( new SensorItem(Sensor.TYPE_SIGNIFICANT_MOTION, "SIGNIFICANT_MOTION"));
    sensorList.add( new SensorItem(Sensor.TYPE_STEP_COUNTER, "STEP_COUNTER"));
    sensorList.add( new SensorItem(Sensor.TYPE_STEP_DETECTOR, "STEP_DETECTOR"));
}

Sensor.TYPE_XXっていうのが、Sensorのページを見るとConstantsの一覧に書いてあって、「Class representing a sensor. Use getSensorList(int) to get the list of available Sensors.」とされているので、まあ、やりたいことのほとんどはこの辺りのドキュメントに書いてある感じですね。

このSensorManagerから取得するSensor.TYPE_XXXに対応する名前の文字列を保持することを目的とした配列というかArrayListになります。

このために使うSensorManager型の変数であるsensorManagerを定義しておきます。sensorManagerはnewするのではなく、getSystemService()でインスタンスを取得するようになっています。

import android.hardware.Sensor;
import android.hardware.SensorManager;

private SensorManager sensorManager; 
sensorManager = (SensorManager)gtSystemService(SENSOR_SERVICE);

List表示のための準備

List表示のためにArrayAdapter型の配列を接続します。そのために、まずArrayAdapter型の変数を宣言します。
List表示するのは、ArrayAdapterは文字列型の配列として宣言します。

private ArrayAdapter<String> adapter;

onCreate()の作成

onCreate() methodを次のように修正します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sensor_list);
    sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
    adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
    setListAdapter(adapter);
    initSensorList();
    listSensors();
}

先に定義したsensorManagerとadapterを初期化します。setListAdapter(adapter); することで、adapterとして定義されるListがListViewに表示されるようになります。

initSensorList(); で、sensorManagerから取得するセンサーのArrayListを作成し、最後のlistSensors(); で、センサーの一覧を取得して、adapterにセンサーのリストを登録します。

listSensors()メソッドの作成

ListSensors()はprivateなmethodです。単に、先に定義したsensorListのArrayListから一つずつSensorItemを取り出して、それをsensorManagerから取得します。

こうして取得したSensorItemをtoString()してできた文字列を、adapterに追加することで、リストに表示されるアイテムの一覧が完成します。

private void listSensors(){
    for(int i=0; i < sensorList.size(); i++) {
        SensorItem si = sensorList.get(i);
        Sensor sensor = sensorManager.getDefaultSensor(si.getSensor());
        if (sensor != null) {
            si.setStatus(true);
        } else {
            si.setStatus(false);
        }
        adapter.add(si.toString());
        (sensorList.get(i)).setStatus(si.getStatus());
    }
}

実行結果

以上のように、sensorListとsensorListNameでAndroidで利用可能なsensorの一覧を予め作成しておいて、ソレらがAndroid機で実装されているかどうかをgetDefaultSensor()で取得できるかどうか?の結果をArrayAdapterに蓄積し、そのArrayAdapterをListActivityに接続すると、以下のスクリーンショットのように、一覧が表示されるようになります。

Screenshot_1496445758.png

ListActivityに表示されるlistItemはそれぞれclickableなので、これをクリックしたら、取得したsensorの値を表示するようにするのは、そんなに大変な拡張ではないはずなので、次はその辺りを目指してみようと思います。

とりあえず、Toastを使って、sensor.toString()の値を返す例は、以下に書いておきます。

@Override
protected void onListItemClick(ListView lv, View v, int position, long id) {
    SensorItem si = sensorList.get(position);
    Sensor sensor = sensorManager.getDefaultSensor(si.getSensor());

    StringBuilder sb = new StringBuilder();
    if (sensor != null) {
        sb.append(sensor.toString());
    } else {
        sb.append(getString(R.string.empty_text));
    }
    Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
}

sensorの値の取得

sensorの値を取得するには、値を取得するためのリスナーを作成して登録しておく必要があります。

これは、sensorの種類ごとに取得できる値も異なるので、sensorの種類の数だけ場合分けをしたmethodを書く必要があるのかもしれません。
SensorManagerのページにregisterListener()が複数定義されていることからも、なんとなく想像がつきます。

参考文献

本日のコード

fukuit
最近、事務系の職場に異動したので、職業プログラマではなくなりました。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away