センサーの概要

ほとんどの Android 搭載デバイスには、動き、向き、さまざまな環境条件を測定するセンサーが組み込まれています。これらのセンサーは、高精度かつ正確に元データを提供できるため、デバイスの 3 次元の動きや位置をモニタリングする場合や、デバイスの近くの環境環境の変化をモニタリングする場合に便利です。たとえば、ゲームはデバイスの重力センサーの測定値を追跡して、傾斜、シェイク、回転、スイングなどの複雑なユーザーの操作や動きを推測できます。同様に、天気アプリは、デバイスの温度センサーと湿度センサーを使用して露点温度を計算して報告します。旅行アプリでは、地磁気センサーと加速度計を使用してコンパス方位を報告します。

Android プラットフォームは、大きく分けて次の 3 つのカテゴリのセンサーをサポートしています。

  • モーション センサー

    3 軸方向の加速力や回転力を測定するためのセンサーです。このカテゴリには、加速度計、重力センサー、ジャイロスコープ、回転ベクトル センサーが含まれます。

  • 環境センサー

    これらのセンサーは、周囲の気温や気圧、照度、湿度など、さまざまな環境パラメータを測定します。このカテゴリには、気圧計、光度計、温度計が含まれます。

  • 位置センサー

    デバイスの物理的な位置を測定するためのセンサーです。このカテゴリには、方向センサーや磁力計が含まれます。

Android センサー フレームワークを使用して、デバイスで利用可能なセンサーにアクセスし、未加工のセンサーデータを取得できます。センサー フレームワークには、センサー関連のさまざまなタスクの実行に役立つクラスとインターフェースがいくつか用意されています。たとえば、このセンサー フレームワークを使用して次のことを行えます。

  • そのデバイスで使用できるセンサーを特定する。
  • 個々のセンサーの機能(最大範囲、メーカー、消費電力、解像度など)を決定します。
  • センサーから測定データを取得する。また、測定データを取得する際の最低速度を定義する。
  • センサーの変化をモニタリングするセンサー イベント リスナーの登録や登録解除を行う。

このトピックでは、Android プラットフォームで利用可能なセンサーの概要について説明します。また、Android センサー フレームワークの概要についても説明します。

センサーの概要

Android センサー フレームワークでは、さまざまなタイプのセンサーを利用できます。これらのセンサーには、ハードウェアベースとソフトウェアベースのものがあります。ハードウェア ベースのセンサーは、スマートフォンやタブレット デバイスに組み込まれた物理コンポーネントです。加速度、地磁気強度、角度変化などの特定の環境特性を直接測定することで、データを導出します。ソフトウェアベースのセンサーは物理デバイスではありませんが、ハードウェア ベースのセンサーを模倣したものです。ソフトウェア ベースのセンサーは、1 つ以上のハードウェア ベースのセンサーからデータを取得します。仮想センサーまたは合成センサーと呼ばれることもあります。ソフトウェアベースのセンサーには、線形加速度センサーや重力センサーなどがあります。表 1 に、Android プラットフォームでサポートされているセンサーの概要を示します。

すべてのタイプのセンサーを備えた Android 搭載デバイスはまれにしかありません。たとえば、ほとんどのハンドセット デバイスとタブレットには加速度計と磁力計がありますが、気圧計や温度計を搭載しているデバイスはほとんどありません。また、1 つのデバイスに同じタイプのセンサーが複数搭載されていることもあります。たとえば、デバイスに 2 つの重力センサーがあり、それぞれ範囲が異なる場合があります。

表 1. Android プラットフォームでサポートされているセンサータイプ

センサー タイプ 説明 一般的な活用法
TYPE_ACCELEROMETER ハードウェア 重力を含む、3 つの物理軸(x、y、z)すべてでデバイスに適用される加速度を m/s2 単位で測定します。 動きの検出(シェイク、ティルトなど)。
TYPE_AMBIENT_TEMPERATURE ハードウェア 周囲の室温を摂氏(°C)単位で測定します。下記の注をご覧ください。 気温のモニタリング。
TYPE_GRAVITY ソフトウェアまたはハードウェア デバイスに適用される 3 つの物理軸(x、y、z)すべてにかかる重力を m/s2 単位で測定します。 動きの検出(シェイク、ティルトなど)。
TYPE_GYROSCOPE ハードウェア 3 つの物理軸(x、y、z)のそれぞれを中心とするデバイスの回転速度を rad/s で測定します。 回転の検出(スピン、ターンなど)。
TYPE_LIGHT ハードウェア 周囲光レベル(照度)をルクス単位で測定します。 画面の明るさの制御。
TYPE_LINEAR_ACCELERATION ソフトウェアまたはハードウェア デバイスに適用される 3 つの物理軸(x、y、z)すべてで、重力を除き、加速度を m/s2 単位で測定します。 1 軸方向の加速度のモニタリング。
TYPE_MAGNETIC_FIELD ハードウェア 3 つの物理軸(x、y、z)すべてについて、周囲の地磁気を μT 単位で測定します。 コンパスの作成。
TYPE_ORIENTATION ソフトウェア デバイスが 3 つの物理軸(x、y、z)のまわりに行う回転の度数を測定します。API レベル 3 以降では、重力センサーと地磁場センサーを getRotationMatrix() メソッドと組み合わせて使用することで、デバイスの傾斜行列と回転行列を取得できます。 デバイスの姿勢の特定。
TYPE_PRESSURE ハードウェア 周囲の気圧をヘクトパスカル(ミリバール)単位で測定します。 気圧変化のモニタリング。
TYPE_PROXIMITY ハードウェア デバイスのビュー画面に対する物体の近さを cm 単位で測定します。このセンサーは通常、ハンドセットが人の耳に当てられているかどうかを判断するために使用されます。 通話中のスマートフォンの位置。
TYPE_RELATIVE_HUMIDITY ハードウェア 周囲の相対湿度を百分率(%)で測定します。 露点温度、絶対湿度、相対湿度のモニタリング。
TYPE_ROTATION_VECTOR ソフトウェアまたはハードウェア デバイスの回転ベクトルの 3 つの要素を指定して、デバイスの向きを測定します。 動きの検出と回転の検出。
TYPE_TEMPERATURE ハードウェア デバイスの温度を摂氏(°C)単位で測定します。このセンサーの実装はデバイスによって異なります。このセンサーは、API レベル 14 で TYPE_AMBIENT_TEMPERATURE センサーに置き換えられました。 温度のモニタリング。

センサー フレームワーク

Android センサー フレームワークを使用して、これらのセンサーにアクセスし、未加工のセンサーデータを取得できます。センサー フレームワークは android.hardware パッケージの一部であり、次のクラスとインターフェースが含まれています。

SensorManager
このクラスを使用して、センサー サービスのインスタンスを作成できます。このクラスには、センサーへのアクセスと一覧表示、センサー イベント リスナーの登録と登録解除、方向情報の取得を行うためのさまざまなメソッドが用意されています。このクラスには、センサーの精度の報告、データ取得レートの設定、センサーの調整に使用されるセンサー定数もいくつか用意されています。
Sensor
このクラスを使用して、特定のセンサーのインスタンスを作成できます。このクラスには、センサーの機能を判定できるさまざまなメソッドが用意されています。
SensorEvent
システムはこのクラスを使用して、センサー イベントに関する情報を提供するセンサー イベント オブジェクトを作成します。センサー イベント オブジェクトには、未加工のセンサーデータ、イベントを生成したセンサーのタイプ、データの精度、イベントのタイムスタンプなどの情報が含まれます。
SensorEventListener
このインターフェースを使用して、センサー値が変更されたとき、またはセンサーの精度が変更されたときに通知(センサー イベント)を受信する 2 つのコールバック メソッドを作成できます。

通常のアプリでは、上記のセンサー関連 API を使用して、次の 2 つの基本的なタスクを行います。

  • センサーとセンサー機能の特定

    センサーとセンサー機能を実行時に識別することは、特定のセンサータイプや機能に依存する機能がアプリにある場合に役立ちます。たとえば、デバイスに搭載されているセンサーをすべて特定し、搭載されていないセンサーに依存するアプリ機能を無効にできます。同様に、特定のタイプのセンサーをすべて特定して、アプリに最適なパフォーマンスを持つセンサーの実装を選択することをおすすめします。

  • センサー イベントをモニタリングする

    センサーから測定データを取得するには、センサー イベントをモニタリングします。センサー イベントは、測定中のパラメータの変化をセンサーが検出するたびに発生します。センサー イベントからは、イベントをトリガーしたセンサーの名前、イベントのタイムスタンプ、イベントの精度、イベントをトリガーしたセンサーの未加工データという 4 つの情報が提供されます。

センサー対応状況

センサーの提供状況はデバイスによって異なりますが、Android のバージョンによっても異なります。これは、Android センサーが複数のプラットフォーム リリースで導入されたためです。たとえば、多くのセンサーは Android 1.5(API レベル 3)で導入されましたが、一部のセンサーは実装されておらず、Android 2.3(API レベル 9)まで使用できません。同様に、Android 2.3(API レベル 9)と Android 4.0(API レベル 14)でいくつかのセンサーが導入されました。2 つのセンサーのサポートが終了し、より新しい高性能なセンサーに置き換えられました。

表 2 に、プラットフォームごとのセンサー対応状況をまとめます。ここでは、センサーの変更に関与したプラットフォームが 4 つだけ表示されています。非推奨としてリストされているセンサーは、Android の上位互換性ポリシーに従って、後続のプラットフォームで引き続き使用できます(デバイスにセンサーが存在する場合)。

表 2. プラットフォームごとのセンサー対応状況

センサー Android 4.0
(API Level 14)
Android 2.3
(API Level 9)
Android 2.2
(API Level 8)
Android 1.5
(API Level 3)
TYPE_ACCELEROMETER はい
TYPE_AMBIENT_TEMPERATURE × - -
TYPE_GRAVITY はい × -
TYPE_GYROSCOPE はい ×1 ×1
TYPE_LIGHT はい
TYPE_LINEAR_ACCELERATION × -
TYPE_MAGNETIC_FIELD はい はい
TYPE_ORIENTATION 2 2 2 はい
TYPE_PRESSURE ×1 ×1
TYPE_PROXIMITY はい
TYPE_RELATIVE_HUMIDITY × - -
TYPE_ROTATION_VECTOR はい × -
TYPE_TEMPERATURE 2 はい はい

1 このセンサータイプは Android 1.5(API レベル 3)で追加されましたが、Android 2.3(API レベル 9)までは使用できませんでした。

2 このセンサーは利用可能ですが、非推奨になりました。

センサーとセンサー性能の特定

Android センサー フレームワークには、実行時にデバイス上のセンサーを簡単に判別できる方法がいくつか用意されています。この API には、各センサーの機能(最大範囲、解像度、電力要件など)を判別できるメソッドも用意されています。

デバイスに搭載されているセンサーを特定するには、まずセンサー サービスへの参照を取得する必要があります。そのためには、getSystemService() メソッドを呼び出して SENSOR_SERVICE 引数を渡して、SensorManager クラスのインスタンスを作成します。次に例を示します。

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

次に、getSensorList() メソッドを呼び出し、TYPE_ALL 定数を使用することで、デバイス上のすべてのセンサーのリストを取得できます。次に例を示します。

Kotlin

val deviceSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

Java

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

特定のタイプのセンサーをすべて一覧表示する場合は、TYPE_ALL の代わりに別の定数(TYPE_GYROSCOPETYPE_LINEAR_ACCELERATIONTYPE_GRAVITY など)を使用できます。

また、getDefaultSensor() メソッドを使用して、特定のセンサーのタイプ定数を渡すことで、特定のタイプのセンサーがデバイスに存在するかどうかを判断することもできます。デバイスに特定のタイプのセンサーが複数ある場合は、そのうちの 1 つをデフォルト センサーとして指定する必要があります。特定のタイプのセンサーにデフォルトのセンサーが存在しない場合、メソッド呼び出しは null を返します。つまり、デバイスにそのタイプのセンサーがないことを意味します。たとえば、次のコードでは、デバイス上に磁力計があるかどうかを確認しています。

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
    // Success! There's a magnetometer.
} else {
    // Failure! No magnetometer.
}

注: Android では、デバイス メーカーが Android 搭載デバイスに特定のタイプのセンサーを組み込むことを要求していないため、さまざまなセンサー構成を使用できます。

デバイスに搭載されているセンサーを一覧表示するだけでなく、Sensor クラスのパブリック メソッドを使用して、個々のセンサーの機能と属性を判別することもできます。これは、デバイスで使用できるセンサーやセンサー機能に応じてアプリの動作を変える場合に便利です。たとえば、getResolution() メソッドと getMaximumRange() メソッドを使用して、センサーの解像度と最大測定範囲を取得できます。getPower() メソッドを使用して、センサーの所要電力を取得することもできます。

2 つのパブリック メソッドが特に役立つのは、さまざまなメーカーのセンサーやセンサーのバージョンに合わせてアプリを最適化する場合です。たとえば、アプリが傾斜やシェイクなどのユーザー操作をモニタリングする必要がある場合は、特定のベンダーの重力センサーを備えた新しいデバイス向けにデータ フィルタリング ルールと最適化のセットを 1 つ作成し、重力センサーがなく加速度計のみを備えたデバイス用に別のデータ フィルタリング ルールと最適化のセットを作成できます。次のコードサンプルは、getVendor() メソッドと getVersion() メソッドを使用してこれを行う方法を示しています。このサンプルでは、ベンダーとして Google LLC を示し、バージョン番号が 3 の重力センサーを探しています。その特定のセンサーがデバイスに存在しない場合は、加速度計の使用を試みます。

Kotlin

private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null

...

sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
    val gravSensors: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // Use the version 3 gravity sensor.
    mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
    // Use the accelerometer.
    mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
    } else {
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
        null
    }
}

Java

private SensorManager sensorManager;
private Sensor mSensor;

...

sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
    List<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); i++) {
        if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
           (gravSensors.get(i).getVersion() == 3)){
            // Use the version 3 gravity sensor.
            mSensor = gravSensors.get(i);
        }
    }
}
if (mSensor == null){
    // Use the accelerometer.
    if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
        mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    } else{
        // Sorry, there are no accelerometers on your device.
        // You can't play this game.
    }
}

もう 1 つの便利なメソッドは getMinDelay() メソッドです。このメソッドは、センサーがデータを検知するために使用できる最小時間間隔(マイクロ秒単位)を返します。getMinDelay() メソッドに対してゼロ以外の値を返すセンサーは、ストリーミング センサーです。ストリーミング センサーは定期的にデータを検知します。Android 2.3(API レベル 9)で導入されました。getMinDelay() メソッドを呼び出したときにゼロが返された場合、そのセンサーはストリーミング センサーではないことを意味します。これは、検知しているパラメータに変更があった場合にのみデータを報告するためです。

getMinDelay() メソッドは、センサーがデータを取得できる最大レートを決定できるため便利です。アプリの特定の機能で高いデータ取得速度やストリーミング センサーが必要な場合は、この方法を使用して、センサーがそれらの要件を満たしているかどうかを判断し、それに応じてアプリの関連機能を有効または無効にできます。

注意: センサーの最大データ取得速度は、必ずしもセンサー フレームワークがセンサーデータをアプリに配信する速度と同じではありません。センサー フレームワークはセンサー イベントを通じてデータを報告しますが、アプリがセンサー イベントを受信するレートにはいくつかの要因が影響します。詳細については、センサー イベントのモニタリングをご覧ください。

センサー イベントのモニタリング

未加工のセンサーデータをモニタリングするには、SensorEventListener インターフェースを通じて公開される 2 つのコールバック メソッド(onAccuracyChanged()onSensorChanged())を実装する必要があります。Android システムは、次の状況が発生するたびにこれらのメソッドを呼び出します。

  • センサーの精度が変化する。

    この場合、システムは onAccuracyChanged() メソッドを呼び出し、変更された Sensor オブジェクトへの参照と、センサーの新しい精度を提供します。精度は、4 つのステータス定数(SENSOR_STATUS_ACCURACY_LOWSENSOR_STATUS_ACCURACY_MEDIUMSENSOR_STATUS_ACCURACY_HIGHSENSOR_STATUS_UNRELIABLE)のいずれかで表されます。

  • センサーが新しい値を報告した。

    この場合、システムは onSensorChanged() メソッドを呼び出し、SensorEvent オブジェクトを提供します。SensorEvent オブジェクトには、データの精度、データを生成したセンサー、データが生成されたタイムスタンプ、センサーが記録した新しいデータなど、新しいセンサーデータに関する情報が含まれます。

次のコードは、onSensorChanged() メソッドを使用して光センサーからのデータをモニタリングする方法を示しています。この例では、main.xml ファイルで sensor_data として定義されている TextView に未加工のセンサーデータが表示されます。

Kotlin

class SensorActivity : Activity(), SensorEventListener {
    private lateinit var sensorManager: SensorManager
    private var mLight: Sensor? = null

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)

        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
    }

    override fun onSensorChanged(event: SensorEvent) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        val lux = event.values[0]
        // Do something with this sensor value.
    }

    override fun onResume() {
        super.onResume()
        mLight?.also { light ->
            sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {
    private SensorManager sensorManager;
    private Sensor mLight;

    @Override
    public final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
    }

    @Override
    public final void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
    }

    @Override
    public final void onSensorChanged(SensorEvent event) {
        // The light sensor returns a single value.
        // Many sensors return 3 values, one for each axis.
        float lux = event.values[0];
        // Do something with this sensor value.
    }

    @Override
    protected void onResume() {
        super.onResume();
        sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
    }

    @Override
    protected void onPause() {
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

この例では、デフォルトのデータ遅延(SENSOR_DELAY_NORMAL)を、registerListener() メソッドが呼び出されたときに指定しています。データ遅延(またはサンプリング レート)は、onSensorChanged() コールバック メソッドを介してセンサー イベントがアプリに送信される間隔を制御します。デフォルトのデータ遅延は一般的な画面の向きの変化をモニタリングするのに適しており、200,000 マイクロ秒の遅延を使用します。SENSOR_DELAY_GAME(20,000 マイクロ秒の遅延)、SENSOR_DELAY_UI(60,000 マイクロ秒の遅延)、SENSOR_DELAY_FASTEST(0 マイクロ秒の遅延)など、その他のデータ遅延を指定できます。Android 3.0(API レベル 11)以降では、遅延を絶対値(マイクロ秒単位)で指定することもできます。

指定した遅延は希望値にすぎません。Android システムやその他のアプリは、この遅延を変更することができます。ベスト プラクティスとして、可能な限り最大の遅延を指定してください。システムは通常、指定した遅延よりも小さい遅延を使用します(つまり、アプリケーションのニーズを満たしながら最も遅いサンプリング レートを選択します)。遅延を大きくすると、プロセッサの負荷が小さくなるため、消費電力が少なくなります。

センサー フレームワークがセンサー イベントをアプリに送信するレートを特定する公開メソッドはありません。ただし、各センサー イベントに関連付けられているタイムスタンプを使用して、複数のイベントに対するサンプリング レートを計算できます。サンプリング レート(遅延)を設定した後に変更する必要はありません。なんらかの理由で遅延を変更する必要がある場合は、センサー リスナーの登録を解除して再登録する必要があります。

また、この例では onResume() コールバック メソッドと onPause() コールバック メソッドを使用して、センサー イベント リスナーの登録と登録解除を行っています。ベスト プラクティスとして、特にアクティビティが一時停止されている場合は、不要なセンサーを常に無効にすることをおすすめします。これを怠ると、センサーによっては電力要件が厳しく、バッテリーの電力が急激に消費されてしまうため、数時間でバッテリーが消耗する可能性があります。画面がオフになっても、センサーが自動的に無効になることはありません。

さまざまなセンサー構成への対応

Android ではデバイスの標準センサー構成が指定されていません。つまり、デバイス メーカーは、任意のセンサー構成を Android 搭載デバイスに組み込むことができます。そのため、デバイスに搭載されているセンサーの構成はさまざまです。アプリが特定の種類のセンサーに依存している場合は、アプリを正常に実行できるように、デバイスにセンサーが存在することを確認する必要があります。

デバイスに特定のセンサーが存在することを確認するには、次の 2 つの方法があります。

  • ランタイムにセンサーを検出し、その結果に応じてアプリの機能を有効または無効にする。
  • Google Play フィルタを使用して、特定のセンサー構成のデバイスのみをターゲットにする。

それぞれの方法について、以下のセクションで説明します。

ランタイムにおけるセンサーの検出

アプリが特定のタイプのセンサーを使用しているが、それに依存していない場合は、センサー フレームワークを使用して実行時にセンサーを検出し、必要に応じてアプリの機能を無効または有効にできます。たとえば、ナビゲーション アプリでは、温度センサー、圧力センサー、GPS センサー、地磁場センサーを使用して、温度、気圧、位置情報、コンパス方位を表示できます。デバイスに圧力センサーがない場合は、センサー フレームワークを使用して、実行時に圧力センサーがないことを検出し、アプリの UI で圧力を表示する部分を無効にできます。たとえば、次のコードはデバイスに圧力センサーがあるかどうかを確認します。

Kotlin

private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager

if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) {
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Java

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
    // Success! There's a pressure sensor.
} else {
    // Failure! No pressure sensor.
}

Google Play フィルタを使用したセンサー構成によるターゲットの絞り込み

アプリを Google Play で公開する場合は、マニフェスト ファイルで <uses-feature> 要素を使用すると、アプリに適したセンサー設定がないデバイスからアプリを除外できます。<uses-feature> 要素には、特定のセンサーの有無に基づいてアプリをフィルタリングできる複数のハードウェア記述子があります。一覧表示できるセンサーには、加速度計、気圧計、コンパス(地球磁場)、ジャイロスコープ、光、近接センサーがあります。加速度計を備えていないアプリをフィルタするマニフェスト エントリの例を次に示します。

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

この要素と記述子をアプリのマニフェストに追加すると、デバイスに加速度計が搭載されている場合にのみ、ユーザーには Google Play でアプリが表示されます。

アプリが特定のセンサーに完全に依存している場合にのみ、記述子を android:required="true" に設定する必要があります。アプリの一部の機能にセンサーを使用しているが、そのセンサーがなくても動作する場合は、<uses-feature> 要素にセンサーをリストし、記述子を android:required="false" に設定する必要があります。これにより、特定のセンサーが搭載されていなくてもアプリをインストールできます。これは、アプリケーションで使用する機能を追跡するのに役立つプロジェクト管理のベスト プラクティスでもあります。アプリが特定のセンサーを使用していて、そのセンサーがなくても動作する場合は、実行時にセンサーを検出し、必要に応じてアプリの機能を無効または有効にする必要があります。

センサーの座標系

一般に、センサー フレームワークは標準の 3 軸座標系を使用してデータ値を表現します。ほとんどのセンサーでは、座標系は、デバイスがデフォルトの向き(図 1 を参照)で保持されているときに、デバイスの画面を基準として定義されます。デバイスをデフォルトの向きに保持すると、X 軸は水平で右を向き、Y 軸は垂直で上を向き、Z 軸は画面表面の外側を指しています。このシステムでは、画面の背後の座標は負の Z 値になります。この座標系は、以下のセンサーで使用されます。

図 1. センサー API で使用される座標系(デバイスを基準とする)。

この座標系について理解しておくべき最も重要な点は、デバイスの画面の向きが変わっても軸は入れ替わらないことです。つまり、デバイスが移動してもセンサーの座標系は変化しないということです。この動作は、OpenGL 座標系の動作と同じです。

また、アプリはデバイスの自然な向き(デフォルト)を縦向きと想定してはならないことも理解しておくべきです。多くのタブレット デバイスでは、自然な向きは横向きになっています。また、センサー座標系は常にデバイスの自然な向きに基づきます。

最後に、アプリがセンサーデータと画面上のディスプレイを照合する場合は、getRotation() メソッドを使用して画面の回転を判断してから、remapCoordinateSystem() メソッドを使用してセンサーの座標を画面の座標にマッピングする必要があります。マニフェストで縦向きのみのディスプレイを指定している場合でも、この操作を行う必要があります。

注: 一部のセンサーやメソッドでは、(デバイスの参照フレームではなく)ワールドの基準座標系を基準とする座標系が使用されます。これらのセンサーとメソッドは、地球に対するデバイスの動きやデバイスの位置を表すデータを返します。詳しくは、getOrientation() メソッド、getRotationMatrix() メソッド、方位センサー回転ベクトル センサーをご覧ください。

センサーのレート制限

Android 12(API レベル 31)以降をターゲットとするアプリの場合、ユーザーに関する潜在的な機密情報を保護するために、システムは特定のモーション センサーや位置センサーからのデータの更新頻度を制限します。このデータには、デバイスの加速度計ジャイロスコープ地磁気センサーによって記録された値が含まれます。

リフレッシュ レートの制限は、センサーデータへのアクセス方法によって異なります。

アプリでモーション センサー データをより高いレートで収集する必要がある場合は、次のコード スニペットに示すように HIGH_SAMPLING_RATE_SENSORS 権限を宣言する必要があります。この権限を宣言せずにアプリがモーション センサーのデータを高い頻度で収集しようとすると、SecurityException が発生します。

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

センサーへのアクセスと使用におけるベスト プラクティス

センサーの実装を設計する際は、このセクションで説明するガイドラインに従ってください。このガイドラインは、センサー フレームワークを使用してセンサーにアクセスし、センサーデータを取得するユーザーに推奨されるベスト プラクティスです。

フォアグラウンドでのみセンサーデータを収集する

Android 9(API レベル 28)以降を搭載しているデバイスでは、バックグラウンドで実行されているアプリに次の制限があります。

  • 加速度計やジャイロスコープなど、連続レポートモードを使用するセンサーは、イベントを受信しません。
  • 変更時またはワンショット レポートモードを使用するセンサーは、イベントを受信しません。

こうした制限があるため、アプリがフォアグラウンドにあるとき、またはフォアグラウンド サービスの一部である場合に、センサー イベントを検出することをおすすめします。

センサー リスナーの登録を解除する

センサーの使用が終了したら、またはセンサーのアクティビティが一時停止したら、センサーのリスナーの登録を解除してください。センサー リスナーが登録されていて、そのアクティビティが一時停止されている場合、センサーの登録を解除しない限り、センサーは引き続きデータを取得し、バッテリー リソースを使用します。次のコードは、onPause() メソッドを使用してリスナーの登録を解除する方法を示しています。

Kotlin

private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}

Java

private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

詳しくは unregisterListener(SensorEventListener) をご覧ください。

Android Emulator でテストする

Android Emulator には、加速度計、周囲温度、磁力計、近接、光などのセンサーをテストできる一連の仮想センサー コントロールが含まれています。

エミュレータは、SdkControllerSensor アプリを実行している Android デバイスとの接続を使用します。このアプリは、Android 4.0(API レベル 14)以降を搭載しているデバイスでのみ使用できます。(デバイスに Android 4.0 が搭載されている場合は、リビジョン 2 がインストールされている必要があります)。SdkControllerSensor アプリは、デバイス上のセンサーの変更を監視し、エミュレータに送信します。エミュレータはその後、デバイスのセンサーから受け取った新しい値に基づいて変換されます。

SdkControllerSensor アプリのソースコードは、次の場所で確認できます。

$ your-android-sdk-directory/tools/apps/SdkController

デバイスとエミュレータの間でデータを転送するには、次の手順を行います。

  1. デバイスで USB デバッグが有効になっていることを確認します。
  2. USB ケーブルを使用してデバイスを開発用マシンに接続します。
  3. デバイス側で SdkControllerSensor アプリを起動します。
  4. SdkControllerSensor アプリで、エミュレートするセンサーを選択します。
  5. 次の adb コマンドを実行します。

  6. $ adb forward tcp:1968 tcp:1968
    
  7. Android Emulator を起動します。これで、デバイスを動かすことで、エミュレータに変換を適用できるようになりました。

注: 実機を動かしてもエミュレータが変形しない場合は、ステップ 5 の adb コマンドをもう一度実行してみてください。

詳しくは、Android Emulator ガイドをご覧ください。

onSensorChanged() メソッドをブロックしない

センサーデータは高速に変化する可能性があります。つまり、システムによって onSensorChanged(SensorEvent) メソッドが頻繁に呼び出される可能性があります。ベスト プラクティスとして、onSensorChanged(SensorEvent) メソッド内でのアクションはできる限り少なくし、メソッドをブロックしないようにします。アプリでセンサーデータのフィルタリングや削減を行う必要がある場合は、その作業を onSensorChanged(SensorEvent) メソッドの外部で行う必要があります。

サポートが終了したメソッドやセンサータイプを使用しない

いくつかのメソッドと定数が非推奨になりました。特に、TYPE_ORIENTATION センサータイプは非推奨になりました。向きのデータを取得するには、代わりに getOrientation() メソッドを使用します。同様に、TYPE_TEMPERATURE センサータイプのサポートも終了しました。Android 4.0 を搭載しているデバイスでは、代わりに TYPE_AMBIENT_TEMPERATURE センサータイプを使用する必要があります。

センサーを使用する前に確認する

センサーからデータを取得しようとする前に、必ずそのセンサーがデバイス上に存在することを確認します。よく使用されるセンサーであるという理由だけで、センサーが存在するとは限りません。デバイス メーカーは、デバイスに特定のセンサーを用意する必要はありません。

センサーの遅延は慎重に選択する

registerListener() メソッドでセンサーを登録する際は、アプリケーションまたはユースケースに適した配信レートを選択してください。センサーからは、極めて高速にデータが提供される可能性があります。不要な追加データをシステムから送信できるようになると、システム リソースが浪費され、バッテリーの電力も消費されます。