Czujniki pozycji

Platforma Androida udostępnia 2 czujniki, które umożliwiają określenie położenia urządzenia: czujnik pola geomagnetycznego i akcelerometr. Platforma Androida udostępnia też czujnik, który pozwala określić, jak blisko obiektu znajduje się przód urządzenia (tzw. czujnik zbliżeniowy). Czujnik pola geomagnetycznego i czujnik zbliżeniowy są oparte na sprzęcie. Większość producentów telefonów i tabletów wyposaża swoje urządzenia w czujnik pola geomagnetycznego. Podobnie producenci telefonów zwykle instalują czujnik zbliżeniowy, aby określić, kiedy telefon jest trzymany blisko twarzy użytkownika (np. podczas rozmowy telefonicznej). Aby określić orientację urządzenia, możesz użyć odczytów z akcelerometru i czujnika pola geomagnetycznego.

Uwaga: czujnik orientacji został wycofany w Androidzie 2.2 (poziom API 8), a typ czujnika orientacji został wycofany w Androidzie 4.4W (poziom API 20).

Czujniki położenia są przydatne do określania fizycznego położenia urządzenia w świecie. Możesz na przykład użyć czujnika pola geomagnetycznego w połączeniu z akcelerometrem, aby określić pozycję urządzenia względem magnetycznego bieguna północnego. Możesz też użyć tych czujników, aby określić orientację urządzenia w układzie odniesienia aplikacji. Czujniki położenia nie są zwykle używane do monitorowania ruchu urządzenia, takiego jak potrząsanie, przechylanie czy pchnięcie (więcej informacji znajdziesz w sekcji Czujniki ruchu).

Czujnik pola geomagnetycznego i akcelerometr zwracają wielowymiarowe tablice wartości czujników dla każdego elementu SensorEvent. Na przykład czujnik pola geomagnetycznego dostarcza wartości natężenia pola geomagnetycznego dla każdej z 3 osi współrzędnych podczas pojedynczego zdarzenia czujnika. Podobnie czujnik akcelerometru mierzy przyspieszenie zastosowane do urządzenia podczas zdarzenia czujnika. Więcej informacji o układach współrzędnych używanych przez czujniki znajdziesz w artykule o  układach współrzędnych czujników. Czujnik zbliżeniowy podaje jedną wartość dla każdego zdarzenia czujnika. Tabela 1 zawiera podsumowanie czujników położenia obsługiwanych na platformie Androida.

Tabela 1. Czujniki położenia obsługiwane na platformie Androida.

Czujnik Dane zdarzeń z czujnika Opis Jednostki miary
TYPE_GAME_ROTATION_VECTOR SensorEvent.values[0] Składowa wektora obrotu wzdłuż osi X (x * sin(θ/2)). Bez jednostek
SensorEvent.values[1] Składowa wektora obrotu wzdłuż osi Y (y * sin(θ/2)).
SensorEvent.values[2] Składowa wektora obrotu wzdłuż osi Z (Z * sin(θ/2)).
TYPE_GEOMAGNETIC_ROTATION_VECTOR SensorEvent.values[0] Składowa wektora obrotu wzdłuż osi X (x * sin(θ/2)). Bez jednostek
SensorEvent.values[1] Składowa wektora obrotu wzdłuż osi Y (y * sin(θ/2)).
SensorEvent.values[2] Składowa wektora obrotu wzdłuż osi Z (z * sin(θ/2)).
TYPE_MAGNETIC_FIELD SensorEvent.values[0] Natężenie pola geomagnetycznego wzdłuż osi X. μT
SensorEvent.values[1] Natężenie pola geomagnetycznego wzdłuż osi Y.
SensorEvent.values[2] Natężenie pola geomagnetycznego wzdłuż osi Z.
TYPE_MAGNETIC_FIELD_UNCALIBRATED SensorEvent.values[0] Natężenie pola geomagnetycznego (bez kalibracji twardego żelaza) wzdłuż osi X. μT
SensorEvent.values[1] Natężenie pola geomagnetycznego (bez kalibracji twardego żelaza) wzdłuż osi Y.
SensorEvent.values[2] Natężenie pola geomagnetycznego (bez kalibracji twardego żelaza) wzdłuż osi Z.
SensorEvent.values[3] Szacowanie odchylenia żelaza wzdłuż osi X.
SensorEvent.values[4] Szacowanie odchylenia żelaza wzdłuż osi Y.
SensorEvent.values[5] Szacowanie odchylenia żelaza wzdłuż osi Z.
TYPE_ORIENTATION1 SensorEvent.values[0] Azymut (kąt wokół osi Z). Stopnie
SensorEvent.values[1] nachylenie (kąt wokół osi X),
SensorEvent.values[2] Przechylenie (kąt wokół osi Y).
TYPE_PROXIMITY SensorEvent.values[0] Odległość od obiektu2. cm

1 Ten czujnik został wycofany w Androidzie 2.2 (poziom interfejsu API 8), a ten typ czujnika został wycofany w Androidzie 4.4W (poziom interfejsu API 20). Platforma czujników udostępnia alternatywne metody określania orientacji urządzenia, które zostały omówione w sekcji Obliczanie orientacji urządzenia.

2 Niektóre czujniki zbliżeniowe podają tylko wartości binarne, które oznaczają blisko i daleko.

Używanie czujnika wektora obrotu w grze

Czujnik wektora obrotu gry jest identyczny z czujnikiem wektora obrotu, ale nie wykorzystuje pola geomagnetycznego. Dlatego oś Y nie wskazuje północy, ale inny punkt odniesienia. Ten punkt odniesienia może się przesuwać o taki sam rząd wielkości, o jaki żyroskop przesuwa się wokół osi Z.

Czujnik wektora obrotu gry nie wykorzystuje pola magnetycznego, więc względne obroty są dokładniejsze i nie mają na nie wpływu zmiany pola magnetycznego. Użyj tego czujnika w grze, jeśli nie interesuje Cię, gdzie jest północ, a normalny wektor obrotu nie spełnia Twoich potrzeb, ponieważ opiera się na polu magnetycznym.

Poniższy kod pokazuje, jak uzyskać instancję domyślnego czujnika wektora obrotu gry:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GAME_ROTATION_VECTOR);

Używanie czujnika wektora obrotu geomagnetycznego

Czujnik wektora obrotu geomagnetycznego jest podobny do czujnika wektora obrotu, ale nie używa żyroskopu. Dokładność tego czujnika jest mniejsza niż w przypadku zwykłego czujnika wektora obrotu, ale zużywa on mniej energii. Używaj tego czujnika tylko wtedy, gdy chcesz zbierać informacje o obrocie w tle bez nadmiernego zużycia baterii. Ten czujnik jest najbardziej przydatny, gdy jest używany w połączeniu z grupowaniem.

Poniższy kod pokazuje, jak uzyskać instancję domyślnego czujnika wektora obrotu geomagnetycznego:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR);

obliczanie orientacji urządzenia,

Dzięki obliczeniu orientacji urządzenia możesz monitorować jego pozycję względem układu odniesienia Ziemi (konkretnie bieguna północnego). Poniższy kod pokazuje, jak obliczyć orientację urządzenia:

Kotlin

private lateinit var sensorManager: SensorManager
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
val rotationMatrix = FloatArray(9)
SensorManager.getRotationMatrix(rotationMatrix, null, accelerometerReading, magnetometerReading)

// Express the updated rotation matrix as three orientation angles.
val orientationAngles = FloatArray(3)
SensorManager.getOrientation(rotationMatrix, orientationAngles)

Java

private SensorManager sensorManager;
...
// Rotation matrix based on current readings from accelerometer and magnetometer.
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null,
    accelerometerReading, magnetometerReading);

// Express the updated rotation matrix as three orientation angles.
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);

System oblicza kąty orientacji, korzystając z czujnika pola geomagnetycznego urządzenia w połączeniu z akcelerometrem. Za pomocą tych 2 czujników sprzętowych system dostarcza dane dotyczące tych 3 kątów orientacji:

  • Azymut (stopnie obrotu wokół osi -z). Jest to kąt między bieżącym kierunkiem kompasu urządzenia a północą magnetyczną. Jeśli górna krawędź urządzenia jest skierowana na północ magnetyczną, azymut wynosi 0 stopni. Jeśli górna krawędź jest skierowana na południe, azymut wynosi 180 stopni. Podobnie, jeśli górna krawędź jest skierowana na wschód, azymut wynosi 90 stopni, a jeśli górna krawędź jest skierowana na zachód, azymut wynosi 270 stopni.
  • Pochylenie (stopnie obrotu wokół osi X). Jest to kąt między płaszczyzną równoległą do ekranu urządzenia a płaszczyzną równoległą do podłoża. Jeśli trzymasz urządzenie równolegle do podłoża, z dolną krawędzią najbliżej siebie, i przechylisz górną krawędź urządzenia w stronę podłoża, kąt nachylenia stanie się dodatni. Przechylenie w przeciwnym kierunku – odsuwanie górnej krawędzi urządzenia od podłoża – powoduje, że kąt nachylenia staje się ujemny. Zakres wartości wynosi od -90 stopni do 90 stopni.
  • Przechylenie (stopnie obrotu wokół osi Y). Jest to kąt między płaszczyzną prostopadłą do ekranu urządzenia a płaszczyzną prostopadłą do podłoża. Jeśli trzymasz urządzenie równolegle do ziemi, z dolną krawędzią najbliżej siebie, i przechylisz lewą krawędź urządzenia w stronę ziemi, kąt obrotu będzie dodatni. Przechylenie w przeciwnym kierunku – czyli przesunięcie prawej krawędzi urządzenia w stronę podłoża – powoduje, że kąt obrotu staje się ujemny. Zakres wartości wynosi od -180 stopni do 180 stopni.

Uwaga: definicja przechyłu czujnika została zmieniona, aby odzwierciedlała zdecydowaną większość implementacji w ekosystemie czujników geograficznych.

Pamiętaj, że te kąty działają w innym układzie współrzędnych niż ten używany w lotnictwie (w przypadku odchylenia, nachylenia i przechylenia). W systemie lotniczym oś X biegnie wzdłuż dłuższego boku samolotu, od ogona do dziobu.

Czujnik orientacji uzyskuje dane, przetwarzając nieprzetworzone dane z czujnika przyspieszenia i czujnika pola geomagnetycznego. Ze względu na intensywne przetwarzanie danych dokładność i precyzja czujnika orientacji są mniejsze. Konkretnie: ten czujnik jest niezawodny tylko wtedy, gdy kąt obrotu wynosi 0. W związku z tym czujnik orientacji został wycofany w Androidzie 2.2 (poziom API 8), a typ czujnika orientacji został wycofany w Androidzie 4.4W (poziom API 20). Zamiast używać nieprzetworzonych danych z czujnika orientacji, zalecamy użycie metody getRotationMatrix() w połączeniu z metodą getOrientation() do obliczania wartości orientacji, jak pokazano w tym przykładowym kodzie. W ramach tego procesu możesz użyć metody remapCoordinateSystem(), aby przełożyć wartości orientacji na układ odniesienia aplikacji.

Kotlin

class SensorActivity : Activity(), SensorEventListener {

    private lateinit var sensorManager: SensorManager
    private val accelerometerReading = FloatArray(3)
    private val magnetometerReading = FloatArray(3)

    private val rotationMatrix = FloatArray(9)
    private val orientationAngles = FloatArray(3)

    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
    }

    override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

    override fun onResume() {
        super.onResume()

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)?.also { accelerometer ->
            sensorManager.registerListener(
                    this,
                    accelerometer,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
        sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)?.also { magneticField ->
            sensorManager.registerListener(
                    this,
                    magneticField,
                    SensorManager.SENSOR_DELAY_NORMAL,
                    SensorManager.SENSOR_DELAY_UI
            )
        }
    }

    override fun onPause() {
        super.onPause()

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this)
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    override fun onSensorChanged(event: SensorEvent) {
        if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
            System.arraycopy(event.values, 0, accelerometerReading, 0, accelerometerReading.size)
        } else if (event.sensor.type == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading, 0, magnetometerReading.size)
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    fun updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(
                rotationMatrix,
                null,
                accelerometerReading,
                magnetometerReading
        )

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles)

        // "orientationAngles" now has up-to-date information.
    }
}

Java

public class SensorActivity extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private final float[] accelerometerReading = new float[3];
    private final float[] magnetometerReading = new float[3];

    private final float[] rotationMatrix = new float[9];
    private final float[] orientationAngles = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
        // Do something here if sensor accuracy changes.
        // You must implement this callback in your code.
    }

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

        // Get updates from the accelerometer and magnetometer at a constant rate.
        // To make batch operations more efficient and reduce power consumption,
        // provide support for delaying updates to the application.
        //
        // In this example, the sensor reporting delay is small enough such that
        // the application receives an update before the system checks the sensor
        // readings again.
        Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometer != null) {
            sensorManager.registerListener(this, accelerometer,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
        Sensor magneticField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticField != null) {
            sensorManager.registerListener(this, magneticField,
                SensorManager.SENSOR_DELAY_NORMAL, SensorManager.SENSOR_DELAY_UI);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();

        // Don't receive any more updates from either sensor.
        sensorManager.unregisterListener(this);
    }

    // Get readings from accelerometer and magnetometer. To simplify calculations,
    // consider storing these readings as unit vectors.
    @Override
    public void onSensorChanged(SensorEvent event) {
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
          System.arraycopy(event.values, 0, accelerometerReading,
              0, accelerometerReading.length);
        } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
            System.arraycopy(event.values, 0, magnetometerReading,
                0, magnetometerReading.length);
        }
    }

    // Compute the three orientation angles based on the most recent readings from
    // the device's accelerometer and magnetometer.
    public void updateOrientationAngles() {
        // Update rotation matrix, which is needed to update orientation angles.
        SensorManager.getRotationMatrix(rotationMatrix, null,
            accelerometerReading, magnetometerReading);

        // "rotationMatrix" now has up-to-date information.

        SensorManager.getOrientation(rotationMatrix, orientationAngles);

        // "orientationAngles" now has up-to-date information.
    }
}

Zwykle nie trzeba przetwarzać ani filtrować danych o surowych kątach orientacji urządzenia, poza tłumaczeniem układu współrzędnych czujnika na układ odniesienia aplikacji.

Używanie czujnika pola geomagnetycznego

Czujnik pola geomagnetycznego umożliwia monitorowanie zmian w polu magnetycznym Ziemi. Poniższy kod pokazuje, jak uzyskać instancję domyślnego czujnika pola geomagnetycznego:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);

Uwaga: jeśli aplikacja jest kierowana na Androida 12 (poziom API 31) lub nowszego, ten czujnik ma ograniczoną liczbę żądań.

Ten czujnik dostarcza nieprzetworzone dane o natężeniu pola (w μT) dla każdej z 3 osi współrzędnych. Zwykle nie musisz używać tego czujnika bezpośrednio. Zamiast tego możesz użyć czujnika wektora obrotu, aby określić nieprzetworzony ruch obrotowy, lub akcelerometru i czujnika pola geomagnetycznego w połączeniu z metodą getRotationMatrix(), aby uzyskać macierz obrotu i macierz nachylenia. Następnie możesz użyć tych macierzy z metodami getOrientation() i getInclination(), aby uzyskać dane o azymucie i nachyleniu geomagnetycznym.

Uwaga: podczas testowania aplikacji możesz poprawić dokładność czujnika, wykonując urządzeniem ruchy w kształcie ósemki.

Używanie nieskalibrowanego magnetometru

Nieskalibrowany magnetometr jest podobny do czujnika pola geomagnetycznego, ale nie stosuje się w nim kalibracji pola magnetycznego pod kątem zakłóceń od elementów metalowych. Kalibracja fabryczna i kompensacja temperatury są nadal stosowane do pola magnetycznego. Nieskalibrowany magnetometr jest przydatny do obsługi nieprawidłowych szacunków dotyczących twardego żelaza. Ogólnie wartość geomagneticsensor_event.values[0] będzie zbliżona do uncalibrated_magnetometer_event.values[0] - uncalibrated_magnetometer_event.values[3]. To znaczy,

calibrated_x ~= uncalibrated_x - bias_estimate_x

Uwaga: nieskalibrowane czujniki dostarczają bardziej nieprzetworzone wyniki i mogą zawierać pewne błędy, ale ich pomiary zawierają mniej skoków wynikających z korekt zastosowanych podczas kalibracji. Niektóre aplikacje mogą preferować te nieskalibrowane wyniki, ponieważ są one bardziej płynne i wiarygodne. Jeśli na przykład aplikacja próbuje przeprowadzić własną fuzję czujników, wprowadzenie kalibracji może zniekształcić wyniki.

Oprócz pola magnetycznego nieskalibrowany magnetometr podaje też szacunkowe odchylenie twardego żelaza na każdej osi. Poniższy kod pokazuje, jak uzyskać instancję domyślnego nieskalibrowanego magnetometru:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);

Używanie czujnika zbliżeniowego

Czujnik zbliżeniowy pozwala określić, jak daleko od urządzenia znajduje się obiekt. Poniższy kod pokazuje, jak uzyskać instancję domyślnego czujnika zbliżeniowego:

Kotlin

private lateinit var sensorManager: SensorManager
private var sensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)

Java

private SensorManager sensorManager;
private Sensor sensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);

Czujnik zbliżeniowy jest zwykle używany do określania odległości głowy osoby od przedniej części urządzenia (np. gdy użytkownik wykonuje lub odbiera połączenie telefoniczne). Większość czujników zbliżeniowych zwraca odległość bezwzględną w cm, ale niektóre zwracają tylko wartości „blisko” i „daleko”.

Uwaga: na niektórych modelach urządzeń czujnik zbliżeniowy znajduje się pod ekranem, co może powodować pojawianie się migającej kropki na ekranie, gdy jest on włączony.

Poniższy kod pokazuje, jak używać czujnika zbliżeniowego:

Kotlin

class SensorActivity : Activity(), SensorEventListener {

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

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

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY)
    }

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

    override fun onSensorChanged(event: SensorEvent) {
        val distance = event.values[0]
        // Do something with this sensor data.
    }

    override fun onResume() {
        // Register a listener for the sensor.
        super.onResume()

        proximity?.also { proximity ->
            sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL)
        }
    }

    override fun onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause()
        sensorManager.unregisterListener(this)
    }
}

Java

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

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

        // Get an instance of the sensor service, and use that to get an instance of
        // a particular sensor.
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        proximity = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    }

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

    @Override
    public final void onSensorChanged(SensorEvent event) {
        float distance = event.values[0];
        // Do something with this sensor data.
    }

    @Override
    protected void onResume() {
        // Register a listener for the sensor.
        super.onResume();
        sensorManager.registerListener(this, proximity, SensorManager.SENSOR_DELAY_NORMAL);
      }

    @Override
    protected void onPause() {
        // Be sure to unregister the sensor when the activity pauses.
        super.onPause();
        sensorManager.unregisterListener(this);
    }
}

Uwaga: niektóre czujniki zbliżeniowe zwracają wartości binarne, które oznaczają „blisko” lub „daleko”. W takim przypadku czujnik zwykle podaje maksymalną wartość zakresu w stanie oddalenia i mniejszą wartość w stanie zbliżenia. Zazwyczaj wartość „daleko” jest większa niż 5 cm, ale może się różnić w zależności od czujnika. Maksymalny zasięg czujnika możesz określić za pomocą metody getMaximumRange().

Warto też przeczytać