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


[Android端末に搭載されているセンサーの一覧を取得する](http://qiita.com/fukuit/items/b1defaaba3a66ea3d2be)の続きです。

[前回](http://qiita.com/fukuit/items/b1defaaba3a66ea3d2be)、以下のように書きました。

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

ということで、[前回](http://qiita.com/fukuit/items/b1defaaba3a66ea3d2be)書いたコードを、[```getSensorList(int)```](https://developer.android.com/reference/android/hardware/SensorManager.html#getSensorList(int))を使って書き直そうと思います。

# getSensorList()でセンサー一覧を取得する

```getSensorList()``` は、引数として ```Sensor.TYPE_ALL``` を指定すると、List形式でSensorを返します。そこを修正します。

以下のように、自作のSensorItem型のインスタンスのArrayListを作成する```initSensorList()```というメソッドを作っていました。

```java
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"));
}
```

これを、廃して、```onCreate()```の中で、一行で済ませます。

```java
private SensorManager sensorManager;
private List<Sensor> sensorList;

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_sensor_list);

	sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
	sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);
	
	adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
	setListAdapter(adapter);
	listSensors();
}
```

# Sensorのリストを作成しListViewに追加する
``` listSensors() ``` methodにて、adapterに取得したSensorを追加します。

```java
private void listSensors(){
	for (int i=0; i<sensorList.size(); i++){
		Sensor s = sensorList.get(i);
		StringBuilder sb = new StringBuilder();
		sb.append(s.getStringType()).append(": ").append(s.getName());
		adapter.add(sb.toString());
		sensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL);
	}
}
```

for文の最後で、取得したSensorをregisterListener()して、Sensorからの値を取得できるように準備します。

# ListViewにClickedイベントを追加

[前回](http://qiita.com/fukuit/items/b1defaaba3a66ea3d2be)、以下のように書いていたのですが、ToastでSensorの情報を表示するようにしていました。

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

ここを、変更して、ListViewで選んだSensorの情報を表示するフィールドを画面下部に作成し、そこに情報を表示するように大きくlayoutファイルを変更します。

その上で、```onListItemClick()```methodを書き換えます。

```java
private int sensortype = -1;
private TextView sensorType;
private TextView sensorName;
private TextView sensorValue;

@Override
protected void onCreate(Bundle savedInstanceState){
	// ... (略) ... 
	sensorType = (TextView)findViewById(R.id.sensor_type);
	sensorName = (TextView)findViewById(R.id.sensor_name);
	sensorValue = (TextView)findViewById(R.id.sensor_value);
	// ... (略) ... 
}

@Override
protected void onListItemClick(ListView lv, View v, int position, long id){
	Sensor s = sensorList.get(position);
	sensortype = s.getType();
	sensorType.setText(s.getStringType());
	sensorName.setText(s.getName());
	sensorValue.setText(s.toString());
}
```

sensorType, sensorName, sensorValueを備えたLayoutを、以下のように作成します。

```xml
<LinearLayout android:weightSum="5">![Screenshot_1496829244.png](https://qiita-image-store.s3.amazonaws.com/0/15553/e5ad5b78-4164-ac36-370c-14118cc82f9b.png "Screenshot_1496829244.png")

	<LinearLayout android:layout_weight="3">
		<ListView android:id="@android:id/list" />
	</LinearLayout>
	<LinearLayout android:layout_weight="2">
		<TextView android:id="@+id/sensor_type" />
		<TextView android:id="@+id/sensor_name" />
		<TextView android:id="@+id/sensor_value" />
	</LinearLayout>
</LinearLayout>
```

## 動作イメージ

![Screenshot_1496829244.png](https://qiita-image-store.s3.amazonaws.com/0/15553/b5cc6995-330a-84a6-b671-a8136c95a963.png "Screenshot_1496829244.png")

こなれてませんが、こんな感じになります。

# まとめ
以上により、以下のことが可能になりました。

- Sensorの一覧を取得
- Sensorの一覧をクリックしたら、画面下部のフィールドにSensor情報を表示

## 本日のコード

```java
package jp.gr.java_conf.fukuit.sensoractivity;
/**
 * SensorListActivity
 *   Set ListView to SensorName and Status
 */

import java.util.List;
import android.app.ListActivity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorManager;
import android.hardware.SensorEventListener;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class SensorListActivity extends ListActivity implements SensorEventListener{
    private SensorManager sensorManager;
    private List<Sensor> sensorList;
    private ArrayAdapter<String> adapter;

    private int sensortype;

    private TextView sensorType;
    private TextView sensorName;
    private TextView sensorValue;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sensor_list);

        sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
        sensorList = sensorManager.getSensorList(Sensor.TYPE_ALL);

        sensorType = (TextView)findViewById(R.id.sensor_type);
        sensorName = (TextView)findViewById(R.id.sensor_name);
        sensorValue = (TextView)findViewById(R.id.sensor_value);

        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1);
        setListAdapter(adapter);

        listSensors();
    }

    @Override
    protected void onResume() {
        super.onResume();
        listSensors();
    }

    @Override
    protected void onListItemClick(ListView lv, View v, int position, long id) {
        Sensor s = sensorList.get(position);
        sensortype = s.getType();

        sensorType.setText(s.getStringType());
        sensorName.setText(s.getName());
        sensorValue.setText(s.toString());
    }

    private void listSensors(){
        for(int i=0; i < sensorList.size(); i++) {
            Sensor s = sensorList.get(i);
            StringBuilder sb = new StringBuilder();
            sb.append(s.getStringType()).append(": ").append(s.getName());
            adapter.add(sb.toString());
            sensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL);
        }
    }

    @Override
    public void onSensorChanged(SensorEvent event){
        if (sensortype != -1){
            if (event.sensor.getType() == sensortype){
                String value = String.valueOf(event.values[0]);
                sensorValue.setText(value);
            }
        }
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy){
    }
}
```