Обзор датчиков

Большинство устройств на базе Android имеют встроенные датчики, измеряющие движение, ориентацию и различные условия окружающей среды. Эти датчики способны предоставлять высокоточные и достоверные данные и полезны, если вы хотите отслеживать трехмерное движение или положение устройства, или если вы хотите отслеживать изменения окружающей среды рядом с устройством. Например, игра может отслеживать показания датчика гравитации устройства, чтобы определять сложные жесты и движения пользователя, такие как наклон, встряхивание, вращение или качание. Аналогично, приложение для прогноза погоды может использовать датчик температуры и датчик влажности устройства для расчета и сообщения точки росы, или приложение для путешествий может использовать датчик геомагнитного поля и акселерометр для определения направления компаса.

Платформа Android поддерживает три основные категории датчиков:

  • Датчики движения

    Эти датчики измеряют силы ускорения и вращательные силы вдоль трех осей. К этой категории относятся акселерометры, датчики гравитации, гироскопы и датчики вектора вращения.

  • Экологические датчики

    Эти датчики измеряют различные параметры окружающей среды, такие как температура и давление окружающего воздуха, освещенность и влажность. К этой категории относятся барометры, фотометры и термометры.

  • датчики положения

    Эти датчики измеряют физическое положение устройства. К этой категории относятся датчики ориентации и магнитометры.

Вы можете получить доступ к датчикам, установленным на устройстве, и получить необработанные данные с датчиков, используя фреймворк Android Sensor Framework. Этот фреймворк предоставляет несколько классов и интерфейсов, которые помогают выполнять широкий спектр задач, связанных с датчиками. Например, вы можете использовать фреймворк Sensor Framework для выполнения следующих действий:

  • Определите, какие датчики имеются на устройстве.
  • Определите возможности каждого отдельного датчика, такие как максимальная дальность действия, производитель, требования к питанию и разрешение.
  • Получите исходные данные с датчиков и определите минимальную частоту их получения.
  • Регистрируйте и отменяйте регистрацию обработчиков событий датчиков, которые отслеживают изменения показаний датчиков.

В этой теме представлен обзор доступных на платформе Android датчиков. Также здесь дано представление о фреймворке для работы с датчиками.

Введение в сенсоры

Платформа Android Sensor Framework позволяет получить доступ ко многим типам датчиков. Некоторые из этих датчиков являются аппаратными, а некоторые — программными. Аппаратные датчики — это физические компоненты, встроенные в мобильный телефон или планшет. Они получают данные, непосредственно измеряя определенные свойства окружающей среды, такие как ускорение, напряженность геомагнитного поля или изменение угла. Программные датчики не являются физическими устройствами, хотя и имитируют аппаратные датчики. Программные датчики получают данные от одного или нескольких аппаратных датчиков и иногда называются виртуальными или синтетическими датчиками. Примерами программных датчиков являются датчик линейного ускорения и датчик гравитации. В таблице 1 приведено краткое описание датчиков, поддерживаемых платформой Android.

Немногие устройства на базе Android оснащены всеми типами датчиков. Например, большинство мобильных телефонов и планшетов имеют акселерометр и магнитометр, но гораздо меньше устройств имеют барометры или термометры. Кроме того, устройство может иметь более одного датчика одного типа. Например, устройство может иметь два датчика гравитации, каждый из которых имеет разный диапазон измерения.

Таблица 1. Типы датчиков, поддерживаемые платформой Android.

Датчик Тип Описание Распространенные виды применения
TYPE_ACCELEROMETER Аппаратное обеспечение Измеряет силу ускорения в м/ с² , приложенную к устройству по всем трем физическим осям (x, y и z), включая силу тяжести. Обнаружение движения (встряхивание, наклон и т. д.).
TYPE_AMBIENT_TEMPERATURE Аппаратное обеспечение Измеряет температуру окружающей среды в градусах Цельсия (°C). См. примечание ниже. Мониторинг температуры воздуха.
TYPE_GRAVITY Программное или аппаратное обеспечение Измеряет силу тяжести в м/ с² , которая действует на устройство по всем трем физическим осям (x, y, z). Обнаружение движения (встряхивание, наклон и т. д.).
TYPE_GYROSCOPE Аппаратное обеспечение Измеряет скорость вращения устройства в рад/с вокруг каждой из трех физических осей (x, y и z). Обнаружение вращения (поворот, вращение и т. д.).
TYPE_LIGHT Аппаратное обеспечение Измеряет уровень окружающего освещения (освещенность) в лк. Регулировка яркости экрана.
TYPE_LINEAR_ACCELERATION Программное или аппаратное обеспечение Измеряет силу ускорения в м/ с² , приложенную к устройству по всем трем физическим осям (x, y и z), за исключением силы тяжести. Мониторинг ускорения вдоль одной оси.
TYPE_MAGNETIC_FIELD Аппаратное обеспечение Измеряет окружающее геомагнитное поле по всем трем физическим осям (x, y, z) в мкТл. Создание компаса.
TYPE_ORIENTATION Программное обеспечение Измеряет градусы вращения устройства вокруг всех трех физических осей (x, y, z). Начиная с API уровня 3, матрицу наклона и матрицу вращения устройства можно получить, используя датчик гравитации и датчик геомагнитного поля совместно с методом getRotationMatrix() . Определение положения устройства.
TYPE_PRESSURE Аппаратное обеспечение Измеряет атмосферное давление в гПа или мбар. Мониторинг изменений атмосферного давления.
TYPE_PROXIMITY Аппаратное обеспечение Измеряет расстояние до объекта в сантиметрах относительно экрана устройства. Этот датчик обычно используется для определения того, поднесен ли телефон к уху человека. Положение телефона во время разговора.
TYPE_RELATIVE_HUMIDITY Аппаратное обеспечение Измеряет относительную влажность окружающей среды в процентах (%). Мониторинг точки росы, абсолютной и относительной влажности.
TYPE_ROTATION_VECTOR Программное или аппаратное обеспечение Определяет ориентацию устройства, предоставляя три элемента вектора вращения устройства. Обнаружение движения и обнаружение вращения.
TYPE_TEMPERATURE Аппаратное обеспечение Измеряет температуру устройства в градусах Цельсия (°C). Реализация этого датчика различается в зависимости от устройства, и в API уровня 14 он был заменен датчиком TYPE_AMBIENT_TEMPERATURE Контроль температуры.

Сенсорная платформа

Вы можете получить доступ к этим датчикам и получить необработанные данные с них, используя фреймворк датчиков Android. Фреймворк датчиков является частью пакета android.hardware и включает в себя следующие классы и интерфейсы:

SensorManager
Этот класс можно использовать для создания экземпляра службы датчиков. Он предоставляет различные методы для доступа к датчикам и их перечисления, регистрации и отмены регистрации обработчиков событий датчиков, а также для получения информации об ориентации. Кроме того, класс предоставляет несколько констант для датчиков, используемых для определения точности показаний, установки скорости сбора данных и калибровки датчиков.
Sensor
Этот класс позволяет создать экземпляр конкретного датчика. Он предоставляет различные методы, позволяющие определить возможности датчика.
SensorEvent
Система использует этот класс для создания объекта события датчика, который предоставляет информацию о событии датчика. Объект события датчика включает следующую информацию: исходные данные датчика, тип датчика, сгенерировавшего событие, точность данных и метку времени события.
SensorEventListener
С помощью этого интерфейса можно создать два метода обратного вызова, которые будут получать уведомления (события датчика) при изменении значений датчика или при изменении точности датчика.

В типичном приложении вы используете эти API, связанные с датчиками, для выполнения двух основных задач:

  • Идентификация датчиков и их возможностей.

    Идентификация датчиков и их возможностей во время выполнения полезна, если ваше приложение имеет функции, зависящие от определенных типов или возможностей датчиков. Например, вам может потребоваться идентифицировать все датчики, присутствующие на устройстве, и отключить любые функции приложения, которые зависят от отсутствующих датчиков. Аналогично, вам может потребоваться идентифицировать все датчики определенного типа, чтобы выбрать реализацию датчика, обеспечивающую оптимальную производительность для вашего приложения.

  • Мониторинг событий датчиков

    Мониторинг событий, регистрируемых датчиками, — это способ получения необработанных данных с датчиков. Событие, регистрируемое датчиком, происходит каждый раз, когда датчик обнаруживает изменение измеряемых параметров. Событие, регистрируемое датчиком, предоставляет четыре элемента информации: название датчика, вызвавшего событие, метку времени события, точность события и необработанные данные датчика, вызвавшие событие.

Наличие датчиков

Доступность датчиков варьируется от устройства к устройству, а также между версиями Android. Это связано с тем, что датчики Android внедрялись в течение нескольких релизов платформы. Например, многие датчики были введены в Android 1.5 (уровень API 3), но некоторые не были реализованы и стали доступны для использования только в Android 2.3 (уровень API 9). Аналогично, несколько датчиков были введены в Android 2.3 (уровень API 9) и Android 4.0 (уровень API 14). Два датчика были устарели и заменены более новыми и лучшими датчиками.

В таблице 2 приведена сводная информация о доступности каждого датчика по платформам. Указаны только четыре платформы, поскольку именно на них произошли изменения в работе датчиков. Датчики, помеченные как устаревшие, по-прежнему доступны на последующих платформах (при условии наличия датчика на устройстве), что соответствует политике обратной совместимости Android.

Таблица 2. Доступность датчиков по платформам.

Датчик Android 4.0
(Уровень API 14)
Android 2.3
(Уровень API 9)
Android 2.2
(Уровень API 8)
Android 1.5
(Уровень API 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 также предоставляет методы, позволяющие определить возможности каждого датчика, такие как его максимальная дальность действия, разрешение и энергопотребление.

Для идентификации датчиков, установленных на устройстве, сначала необходимо получить ссылку на службу датчиков. Для этого нужно создать экземпляр класса SensorManager , вызвав метод getSystemService() и передав в него аргумент SENSOR_SERVICE . Например:

Котлин

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 . Например:

Котлин

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

Java

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

Если вы хотите вывести список всех датчиков определенного типа, вместо TYPE_ALL можно использовать другую константу, например TYPE_GYROSCOPE , TYPE_LINEAR_ACCELERATION или TYPE_GRAVITY .

Также можно определить наличие на устройстве датчика определенного типа, используя метод getDefaultSensor() и передав в качестве параметра константу типа для конкретного датчика. Если устройство имеет более одного датчика заданного типа, один из датчиков должен быть назначен в качестве датчика по умолчанию. Если датчик по умолчанию для данного типа датчика не существует, вызов метода возвращает null, что означает, что устройство не имеет датчика этого типа. Например, следующий код проверяет наличие магнитометра на устройстве:

Котлин

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 не обязывает производителей устройств встраивать в свои устройства какие-либо конкретные типы датчиков, поэтому устройства могут иметь широкий спектр конфигураций датчиков.

Помимо перечисления датчиков, установленных на устройстве, вы можете использовать открытые методы класса Sensor для определения возможностей и атрибутов отдельных датчиков. Это полезно, если вы хотите, чтобы ваше приложение работало по-разному в зависимости от того, какие датчики или возможности датчиков доступны на устройстве. Например, вы можете использовать методы getResolution() и getMaximumRange() для получения разрешения и максимального диапазона измерения датчика. Вы также можете использовать метод getPower() для получения требований к энергопотреблению датчика.

Два из общедоступных методов особенно полезны, если вы хотите оптимизировать свое приложение для датчиков разных производителей или разных версий датчика. Например, если вашему приложению необходимо отслеживать жесты пользователя, такие как наклон и встряхивание, вы можете создать один набор правил фильтрации данных и оптимизации для более новых устройств, имеющих датчик гравитации определенного производителя, и другой набор правил фильтрации данных и оптимизации для устройств, которые не имеют датчика гравитации и имеют только акселерометр. Следующий пример кода показывает, как можно использовать методы getVendor() и getVersion() для этого. В этом примере мы ищем датчик гравитации, у которого в качестве производителя указана компания Google LLC и номер версии 3. Если этот конкретный датчик отсутствует на устройстве, мы пытаемся использовать акселерометр.

Котлин

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.
    }
}

Еще один полезный метод — getMinDelay() , который возвращает минимальный временной интервал (в микросекундах), который датчик может использовать для сбора данных. Любой датчик, возвращающий ненулевое значение для метода getMinDelay() является потоковым датчиком. Потоковые датчики собирают данные через регулярные интервалы и были введены в Android 2.3 (уровень API 9). Если датчик возвращает ноль при вызове метода getMinDelay() , это означает, что датчик не является потоковым, поскольку он сообщает данные только при изменении параметров, которые он измеряет.

Метод getMinDelay() полезен, поскольку позволяет определить максимальную скорость сбора данных датчиком. Если для работы некоторых функций вашего приложения требуются высокие скорости сбора данных или потоковая передача данных с датчика, вы можете использовать этот метод, чтобы определить, соответствует ли датчик этим требованиям, и затем соответствующим образом включить или отключить соответствующие функции в вашем приложении.

Внимание: максимальная скорость сбора данных датчиком не обязательно совпадает со скоростью передачи данных датчиком в ваше приложение через платформу управления датчиками. Платформа управления датчиками передает данные посредством событий датчика, и на скорость получения событий датчиком вашим приложением влияют несколько факторов. Для получения дополнительной информации см. раздел «Мониторинг событий датчика» .

Мониторинг событий датчиков

Для мониторинга необработанных данных с датчиков необходимо реализовать два метода обратного вызова, предоставляемых интерфейсом SensorEventListener : onAccuracyChanged() и onSensorChanged() . Система Android вызывает эти методы всякий раз, когда происходит следующее:

  • Точность датчика меняется.

    В этом случае система вызывает метод onAccuracyChanged() , предоставляя вам ссылку на объект Sensor , который изменился, и новую точность датчика. Точность представлена ​​одной из четырех констант состояния: SENSOR_STATUS_ACCURACY_LOW , SENSOR_STATUS_ACCURACY_MEDIUM , SENSOR_STATUS_ACCURACY_HIGH или SENSOR_STATUS_UNRELIABLE .

  • Датчик сообщает о новом значении.

    В этом случае система вызывает метод onSensorChanged() , предоставляя вам объект SensorEvent . Объект SensorEvent содержит информацию о новых данных датчика, включая: точность данных, датчик, сгенерировавший данные, метку времени генерации данных и новые данные, которые записал датчик.

Следующий код демонстрирует, как использовать метод onSensorChanged() для отслеживания данных с датчика освещенности. В этом примере необработанные данные датчика отображаются в TextView , определенном в файле main.xml как sensor_data .

Котлин

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 любую желаемую конфигурацию датчиков. В результате устройства могут включать в себя различные датчики в широком диапазоне конфигураций. Если ваше приложение зависит от определенного типа датчика, вы должны убедиться, что этот датчик присутствует на устройстве, чтобы ваше приложение могло успешно работать.

У вас есть два варианта проверки наличия заданного датчика на устройстве:

  • Обнаружение датчиков во время выполнения и включение или отключение соответствующих функций приложения.
  • Используйте фильтры Google Play, чтобы выбрать устройства с определенными конфигурациями датчиков.

Каждый из вариантов рассматривается в следующих разделах.

Обнаружение датчиков во время выполнения

Если ваше приложение использует определенный тип датчика, но не зависит от него, вы можете использовать фреймворк датчиков для обнаружения датчика во время выполнения, а затем отключать или включать функции приложения по мере необходимости. Например, навигационное приложение может использовать датчик температуры, датчик давления, датчик GPS и датчик геомагнитного поля для отображения температуры, барометрического давления, местоположения и азимута компаса. Если устройство не имеет датчика давления, вы можете использовать фреймворк датчиков для обнаружения отсутствия датчика давления во время выполнения, а затем отключить ту часть пользовательского интерфейса вашего приложения, которая отображает давление. Например, следующий код проверяет наличие датчика давления на устройстве:

Котлин

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) или выше, система ограничивает частоту обновления данных с определенных датчиков движения и положения. Эти данные включают значения, регистрируемые акселерометром , гироскопом и датчиком геомагнитного поля устройства.

Ограничение частоты обновления зависит от способа доступа к данным датчиков:

  • Если вы вызываете метод registerListener() для мониторинга событий датчика , частота дискретизации датчика ограничивается 200 Гц. Это справедливо для всех перегруженных вариантов метода registerListener() .
  • При использовании класса SensorDirectChannel частота дискретизации датчика ограничивается значением RATE_NORMAL , которое обычно составляет около 50 Гц.

Если вашему приложению необходимо собирать данные с датчиков движения с более высокой частотой, необходимо объявить разрешение 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() для отмены регистрации слушателя:

Котлин

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.

Эмулятор Android включает в себя набор виртуальных элементов управления датчиками, позволяющих тестировать такие датчики, как акселерометр, датчик температуры окружающей среды, магнитометр, датчик приближения, датчик освещенности и многое другое.

Эмулятор использует соединение с устройством Android, на котором запущено приложение SdkControllerSensor . Обратите внимание, что это приложение доступно только на устройствах под управлением 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. В приложении выберите датчики, которые хотите эмулировать.
  5. Выполните следующую команду adb :

  6. $ adb forward tcp:1968 tcp:1968
    
  7. Запустите эмулятор. Теперь вы сможете применять преобразования к эмулятору, перемещая устройство.

Примечание: Если действия, которые вы совершаете с физическим устройством, не приводят к трансформации эмулятора, попробуйте снова запустить команду adb из шага 5.

Для получения более подробной информации см. руководство по эмулятору Android .

Не блокируйте метод onSensorChanged()

Данные с датчиков могут изменяться с высокой скоростью, а это значит, что система может довольно часто вызывать метод onSensorChanged(SensorEvent) . В качестве лучшей практики следует как можно меньше действий выполнять внутри метода onSensorChanged(SensorEvent) чтобы не блокировать его. Если ваше приложение требует фильтрации или сокращения данных с датчиков, эту работу следует выполнять вне метода onSensorChanged(SensorEvent) .

Избегайте использования устаревших методов или типов датчиков.

Некоторые методы и константы устарели. В частности, тип датчика TYPE_ORIENTATION устарел. Для получения данных об ориентации следует использовать метод getOrientation() . Аналогично, тип датчика TYPE_TEMPERATURE устарел. На устройствах под управлением Android 4.0 следует использовать тип датчика TYPE_AMBIENT_TEMPERATURE .

Перед использованием датчиков проверьте их работоспособность.

Перед тем как пытаться получить с устройства данные, всегда проверяйте наличие на нем датчика. Не следует предполагать наличие датчика только потому, что он часто используется. Производители устройств не обязаны устанавливать в свои устройства какие-либо конкретные датчики.

Тщательно выбирайте задержки датчиков.

При регистрации датчика с помощью метода registerListener() обязательно выберите частоту передачи данных, подходящую для вашего приложения или сценария использования. Датчики могут передавать данные с очень высокой скоростью. Разрешение системе отправлять лишние данные, которые вам не нужны, приводит к нерациональному использованию системных ресурсов и расходу заряда батареи.