SensorManager exposes motion sensors (accelerometer, gyroscope), position sensors (magnetometer) and environmental ones (light, pressure, humidity) through one API: a SensorEventListener receives SensorEvents whose values depend on the type (three axes in m/s² for the accelerometer, lux for light). The same callbackFlow pattern makes a sensor a Flow that unregisters itself:
fun Context.sensorReadings(type: Int): Flow<FloatArray> = callbackFlow {
val manager = getSystemService(SensorManager::class.java)
val sensor = manager.getDefaultSensor(type) ?: run { close(); return@callbackFlow }
val listener = object : SensorEventListener {
override fun onSensorChanged(event: SensorEvent) { trySend(event.values.clone()) }
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) = Unit
}
manager.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI)
awaitClose { manager.unregisterListener(listener) }
}Clone values, because the system may reuse the event object. The emulator's getSensorList() shows its virtual "Goldfish" hardware and the software sensors Android fuses from it (excerpt):
D/BookNestSensor( 6805): accelerometer: Goldfish 3-axis Accelerometer D/BookNestSensor( 6805): light: Goldfish Light sensor ... D/BookNestSensor( 6805): gravity: Gravity Sensor D/BookNestSensor( 6805): rotation_vector: Rotation Vector Sensor
adb -s emulator-5556 emu sensor set acceleration 2.5:9.4:1.2 tilted the virtual phone: the branch screen's accelerometer line went from x 0.0 y 9.8 z 0.0 (upright) to x 2.5 y 9.4 z 1.2 m/s² (figure in Nearest Branch). Sample no faster than needed (SENSOR_DELAY_UI is about 16 Hz).