Аппараты Samsung
Учитывайте тот факт, что некоторые производители порой мудрят с сенсорами. Например, Samsung разместил на своём сайте таблицу возвращаемых значений для своих аппаратов:
Sr No | Galaxy S | Galaxy S II | Range |
(0; 1000) | |||
<1000; 9000 | |||
<9000; 15000) | |||
<15000; …) |
Samsung выложила для разработчиков свой пример, в котором предлагается определять степень освещённости через перечисление LightLevel. В своём примере я добавил их способ: перечисление LightLevel и метод getLightLevelBySensorValue. Показания выводятся в текстовой метке у метода onSensorChanged().
Пример можно проверить на эмуляторе. Выберите раздел Virtual sensors и меняйте значения у секции Lihgt (lux) на вкладке Additional sensors. Для наглядности я наложил окно настроек на эмулятор и ползунком менял значение от 0 до 40000.
Переходим на тёмную сторону
Что касается практического применения, то можете определять степень освещённости и предлагать пользователю переключиться на дневной/ночной режим чтения текста на экране. Например, ночью многие любят читать белый текст на чёрном фоне.
Установите некое пороговое значение, например, 50 люкс для перехода из дневного режима в ночной.
private final int NIGHT = 0;
private final int DAY = 1;
private final int THRESHOLD_LUX = 50;
private int mStatus;
@Override
public void onSensorChanged(SensorEventsensorEvent) {
final LightLevellightLevel = getLightLevelBySensorValue(sensorEvent.values[0]);
if (sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT) {
mLightValueTextView.setText("LIGHT: " + sensorEvent.values[0]);
}
float luxValue = sensorEvent.values[0];
mStatus = luxValue< THRESHOLD_LUX?NIGHT: DAY;
if(mStatus == 0){
// Ночь
mLightValueTextView.setBackgroundColor(Color.BLACK);
mLightValueTextView.setTextColor(Color.WHITE);
}else {
// День
mLightValueTextView.setBackgroundColor(Color.WHITE);
mLightValueTextView.setTextColor(Color.BLACK);
}
}
Припаденииосвещённостименьше 50 люкстекстоваяметкапоменяетсвоицвета.
|
Может случиться так, что устройство будет находится в таком месте, где уровень освещённости будет примерно равен выбранному пороговому значению, колеблясь то в одну, то в другую сторону. Это приведет к тому, что приложение будет очень часто переключаться из одного режима в другой. Для устранения недостатка создадим два пороговых значения: верхнее и нижнее. Всё, что выше верхнего порога будет считаться днём, остальное — ночью, а изменения между порогами будем игнорировать.
//private final int THRESHOLD_LUX = 50;
// выбираемдиапазонзначений
private static final int THRESHOLD_DAY_LUX = 55;
private static final int THRESHOLD_NIGHT_LUX = 45;
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
final LightLevel lightLevel = getLightLevelBySensorValue(sensorEvent.values[0]);
if (sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT) {
mLightValueTextView.setText("LIGHT: " + sensorEvent.values[0]);
}
float luxValue = sensorEvent.values[0];
if (luxValue < THRESHOLD_NIGHT_LUX){
mStatus = NIGHT;
} else if (luxValue > THRESHOLD_DAY_LUX){
mStatus = DAY;
}
if(mStatus == 0){
// Ночь
mLightValueTextView.setBackgroundColor(Color.BLACK);
mLightValueTextView.setTextColor(Color.WHITE);
}else {
// День
mLightValueTextView.setBackgroundColor(Color.WHITE);
mLightValueTextView.setTextColor(Color.BLACK);
}
}
В идеальных условиях данного примера вполне достаточно. Но представьте себе, что вы едете в поезде и тени деревьев за окном приводят к ложным срабатываниям при кратковременном сильном изменении уровня освещённости. Мы можем избавиться от этой проблемы, если установим фильтр низких частот, который сгладит все резкие и кратковременные изменения данных от датчика.
private static final float SMOOTHING = 10;
private final LowPassFilter mLowPassFilter = new LowPassFilter(SMOOTHING);
// вметоде onSensorChanged()
float luxValue = sensorEvent.values[0];
luxValue = mLowPassFilter.submit(luxValue);
|
public class LowPassFilter {
private float filteredValue;
private final float smoothing;
private boolean firstTime = true;
public LowPassFilter(float smoothing) {
this.smoothing = smoothing;
}
public float submit(float newValue){
if (firstTime){
filteredValue = newValue;
firstTime = false;
return filteredValue;
}
filteredValue += (newValue - filteredValue) / smoothing;
return filteredValue;
}
}
Итоговыйвариант:
import android.content.Context;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity implements SensorEventListener {
// фильтрнизкихчастот
private static final float SMOOTHING = 10;
private final LowPassFilter mLowPassFilter = new LowPassFilter(SMOOTHING);
private final int NIGHT = 0;
private final int DAY = 1;
//private final int THRESHOLD_LUX = 50;
private static final int THRESHOLD_DAY_LUX = 55;
private static final int THRESHOLD_NIGHT_LUX = 45;
private int mStatus;
private SensorManager mSensorManager;
private Sensor mLightSensor;
private TextView mLightValueTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mLightValueTextView = (TextView) findViewById(R.id.textViewInfo);
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
if (mLightSensor == null) {
Toast.makeText(getApplicationContext(), "Датчикосвещениянеобнаружен!",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getApplicationContext(), "Датчикосвещения " + mLightSensor.getName()
+ " доступен", Toast.LENGTH_SHORT).show();
}
}
// Лучшеперенестив onStart()
protected void onResume() {
mSensorManager.registerListener(this, mLightSensor, SensorManager.SENSOR_DELAY_UI);
super.onResume();
}
// Лучшеперенестив onStop()
protected void onPause() {
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
|
final LightLevel lightLevel = getLightLevelBySensorValue(sensorEvent.values[0]);
if (sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT) {
mLightValueTextView.setText("LIGHT: " + sensorEvent.values[0] +
"\nLight level: " + lightLevel);
}
float luxValue = sensorEvent.values[0];
luxValue = mLowPassFilter.submit(luxValue);
if (luxValue < THRESHOLD_NIGHT_LUX){
mStatus = NIGHT;
} else if (luxValue > THRESHOLD_DAY_LUX){
mStatus = DAY;
}
//mStatus = luxValue < THRESHOLD_LUX? NIGHT: DAY;
if(mStatus == 0){
// Ночь
mLightValueTextView.setBackgroundColor(Color.BLACK);
mLightValueTextView.setTextColor(Color.WHITE);
}else {
// День
mLightValueTextView.setBackgroundColor(Color.WHITE);
mLightValueTextView.setTextColor(Color.BLACK);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
// Дляаппаратов Samsung
private enum LightLevel {
LIGHT_LVL_UNKNOWN, LIGHT_LVL_1, LIGHT_LVL_2, LIGHT_LVL_3, LIGHT_LVL_4
}
private LightLevel getLightLevelBySensorValue(float sensorValue) {
if (sensorValue < 1000.0) {
return LightLevel.LIGHT_LVL_1;
}
if (sensorValue >= 1000.0 && sensorValue < 9000.0) {
return LightLevel.LIGHT_LVL_2;
}
if (sensorValue >= 9000.0 && sensorValue < 15000.0) {
return LightLevel.LIGHT_LVL_3;
}
if (sensorValue >= 15000) {
return LightLevel.LIGHT_LVL_4;
}
return LightLevel.LIGHT_LVL_UNKNOWN;
}
public class LowPassFilter {
private float filteredValue;
private final float smoothing;
private boolean firstTime = true;
public LowPassFilter(float smoothing) {
this.smoothing = smoothing;
}
public float submit(float newValue){
if (firstTime){
filteredValue = newValue;
firstTime = false;
return filteredValue;
}
filteredValue += (newValue - filteredValue) / smoothing;
return filteredValue;
}
}
}
В заключение можно упомянуть о константах для датчика освещённости: LIGHT_CLOUDY, LIGHT_FULLMOON, LIGHT_SUNRISE и др., которые можете использовать в своих примерах.