Важно (9.07.22)

Если картинки в постах не отображаются, зайдите в блог через прокси. РКН заблокировал поддомены blogger.com на которые загружались картинки.

пятница, 4 июля 2014 г.

Получаем список датчиков и информацию о них


В этой заметке узнаем, как можно получить список установленных в устройстве датчиков(Sensors) и полную информацию о них. Сразу скажу, что метод работает только на Android устройствах. Я хотел использовать «кроссплатформенный» модуль «System.Sensors», но оказалось, что он не может решить данную задачу на Android, об этом я ещё немного напишу ниже.
И вопрос к разработчикам Embarcadero.

Написано на Delphi XE6 и Android 4.1.2.
Upd(2.10.14). Проверено на Delphi XE7 и Android 4.4.2






Для работы с датчиками в Android API есть класс «SensorManager(android.hardware.SensorManager)», он умеет много всего, но нам сегодня понадобится только один метод «getSensorList(int type)».
Метод возвращает список доступных датчиков указанного типа. 

Типы (для Android API10), также можете найти их тут (Sensor(android.hardware.Sensor)):
  • TYPE_ALL: 'Все типы'
  • TYPE_ACCELEROMETER: 'Акселерометр'
  • TYPE_GRAVITY: 'Датчик силы тяжести'
  • TYPE_GYROSCOPE: 'Гироскоп'
  • TYPE_LIGHT: 'Датчик света'
  • TYPE_LINEAR_ACCELERATION: 'Датчик ускорения'
  • TYPE_MAGNETIC_FIELD: 'Датчик магнитного поля'
  • TYPE_ORIENTATION: 'Датчик ориентации'
  • TYPE_PRESSURE: 'Датчик давления'
  • TYPE_PROXIMITY: 'Датчик приближения'
  • TYPE_ROTATION_VECTOR: 'Датчик вращения'
  • TYPE_TEMPERATURE: 'Датчик температуры'
Для получения списка датчиков у нас всё готово. Теперь нам необходимо вывести всю доступную техническую информацию о датчиках из списка, для этого воспользуемся классом «Sensor(android.hardware.Sensor)», который содержит ещё и методы.

Методы (для Android API10):
  • getMaximumRange() – Максимальное значение датчика
  • getMinDelay() – Минимально допустимая задержка между двумя событиями (в микросекундах)
  • getName() – Имя(название) датчика
  • getPower() – Потребляемая мощность (в mA)
  • getResolution() – Разрешающая способность датчика
  • getType() – Тип датчика (число)
  • getVendor() – Производитель датчика
  • getVersion() – Версия датчика
Как видите информации достаточно, чтобы идентифицировать любой установленный на устройстве датчик.
Теперь напишем простейший код для вывода списка датчиков со всей информацией.

Примечание: Т.к. тип датчика возвращается в виде числа, то выглядит это совсем не информативно, я использовал оператор выбора для приведения типа к более информативному виду.

Код:
uses
  android.hardware.SensorManager, android.hardware.Sensor,
  Androidapi.JNI.JavaTypes, FMX.Helpers.android, Androidapi.JNIBridge,
  Androidapi.JNI.GraphicsContentViewText, Androidapi.Helpers;

procedure TForm1.Button1Click(Sender: TObject);
var
  SensorsManagerObj: JObject;
  SensorsManager: JSensorManager;
  Sensors: JList;
  Sensor: JSensor;
  i: Integer;
  StringType: String;
begin
  Memo1.Lines.Clear;

  SensorsManagerObj := SharedActivityContext.getSystemService
    (TJContext.JavaClass.SENSOR_SERVICE);
  SensorsManager := TJSensorManager.Wrap((SensorsManagerObj as ILocalObject)
    .GetObjectID);

  Sensors := SensorsManager.getSensorList(TJSensor.JavaClass.TYPE_ALL);

  Label1.Text := 'Found: ' + IntToStr(Sensors.size) + ' sensors';

  for i := 0 to Sensors.size - 1 do
  begin
    Sensor := TJSensor.Wrap((Sensors.get(i) as ILocalObject).GetObjectID);

    Memo1.Lines.Add('Name: ' + JStringToString(Sensor.getName));

    case Sensor.getType of
      TJSensorTYPE_ACCELEROMETER:
        StringType := 'Акселерометр';
      TJSensorTYPE_GRAVITY:
        StringType := 'Датчик силы тяжести';
      TJSensorTYPE_GYROSCOPE:
        StringType := 'Гироскоп';
      TJSensorTYPE_LIGHT:
        StringType := 'Датчик света';
      TJSensorTYPE_LINEAR_ACCELERATION:
        StringType := 'Датчик ускорения';
      TJSensorTYPE_MAGNETIC_FIELD:
        StringType := 'Датчик магнитного поля';
      TJSensorTYPE_ORIENTATION:
        StringType := 'Датчик ориентации';
      TJSensorTYPE_PRESSURE:
        StringType := 'Датчик давления';
      TJSensorTYPE_PROXIMITY:
        StringType := 'Датчик приближения';
      TJSensorTYPE_ROTATION_VECTOR:
        StringType := 'Датчик вращения';
      TJSensorTYPE_TEMPERATURE:
        StringType := 'Датчик температуры';
    else
      StringType := 'Undefined';
    end;

    Memo1.Lines.Add('Type: ' + StringType);
    Memo1.Lines.Add('Vendor: ' + JStringToString(Sensor.getVendor));
    Memo1.Lines.Add('Version: ' + IntToStr(Sensor.getVersion));
    Memo1.Lines.Add('Resolution: ' + FloatToStr(Sensor.getResolution));
    Memo1.Lines.Add('Max Range: ' + FloatToStr(Sensor.getMaximumRange));
    Memo1.Lines.Add('Power: ' + FloatToStr(Sensor.getPower) + 'mA');
    Memo1.Lines.Add('MinDelay: ' + IntToStr(Sensor.getMinDelay));
    Memo1.Lines.Add('----------------');

  end;
end;

Результат:




Теперь про «System.Sensors».
После того как я написал код для Android API вспомнил, что в Delphi есть «кроссплатформенный» модуль для работы с всевозможными датчиками и решил (основная причина «кроссплатформенность») написать для вас второе решение. Написал код, запустил на устройстве и «увидел фигу», ни какой информации, кроме «Категории (типа)» и «Состояния датчика» у меня не получилось достать.

Код:
uses
  System.Sensors, System.TypInfo;

procedure TForm1.Button2Click(Sender: TObject);
var
  SensorsManager: TSensorManager;
  i: Integer;
  Sensor: TCustomSensor;
begin
  SensorsManager := TSensorManager.Current;
  if SensorsManager.CanActivate then
  begin
    SensorsManager.Activate;

    Memo2.Lines.Clear;
    Label2.Text := 'Found: ' + IntToStr(SensorsManager.Count) + ' sensors';

    for i := 0 to SensorsManager.Count - 1 do
    begin
      Sensor := SensorsManager.Sensors[i];
      Memo2.Lines.Add('Name: ' + Sensor.Name);
      Memo2.Lines.Add('Category: ' + GetEnumName(TypeInfo(TSensorCategory),
        Ord(Sensor.Category)));
      Memo2.Lines.Add('Manufacturer: ' + Sensor.Manufacturer);
      Memo2.Lines.Add('Model: ' + Sensor.Model);
      Memo2.Lines.Add('State: ' + GetEnumName(TypeInfo(TSensorState),
        Ord(Sensor.State)));
      Memo2.Lines.Add('SerialNo: ' + Sensor.SerialNo);
      Memo2.Lines.Add('Description: ' + Sensor.Description);
      Memo2.Lines.Add('UniqueID: ' + Sensor.UniqueID);
      Memo2.Lines.Add('----------------');
    end;
  end;
  SensorsManager.Current.Deactivate;
end;

Результат:


Вопрос к разработчикам Embarcadero: Вы планируете «допилить» этот модуль до кроссплатформенного состояния?

На этом всё. Спасибо за внимание!

Исходный код: Скачать с Google Drive