package net.osmand.plus.activities; import java.util.Date; import java.util.List; import java.util.TimeZone; import net.osmand.Location; import net.osmand.PlatformUtil; import net.osmand.StateChangedListener; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandSettings.CommonPreference; import net.osmand.plus.OsmandSettings.DayNightMode; import net.osmand.util.SunriseSunset; import org.apache.commons.logging.Log; import android.content.Context; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; import android.location.LocationManager; /** * Class to help determine if we want to render day or night map - it uses the * DayNightMode enumeration for its behavior<BR> * - it uses the LightSensor and needs calls from MapActivity on onPause and onResume to * register/unregister the sensor listener<BR> * - it uses the {@link SunriseSunset} and {@link LocationManager} to find * out about sunset/sunrise and use it * * Note: the usage of SunriseSunset is not optimized in any way, it is * recalculated on each demand. If this way it would be resource consuming, some * recalculation threshold could be specified to recalculate the sun-rise/set * only sometimes.<BR> * Note2: the light sensor threshold is hard coded to * {@link SensorManager#LIGHT_CLOUDY} and could be made customizable * * @author pavol.zibrita */ public class DayNightHelper implements SensorEventListener { private static final Log log = PlatformUtil.getLog(DayNightHelper.class); private final OsmandApplication osmandApplication; private CommonPreference<DayNightMode> pref; public DayNightHelper(OsmandApplication osmandApplication) { this.osmandApplication = osmandApplication; pref = osmandApplication.getSettings().DAYNIGHT_MODE; } private DayNightHelper listener; private long lastTime = 0; private boolean lastNightMode = false; private StateChangedListener<Boolean> sensorStateListener; public boolean isNightModeForMapControls() { if (osmandApplication.getSettings().isLightContent()) { return isNightMode(); } else { return true; } } /** * @return null if could not be determined (in case of error) * @return true if day is supposed to be */ public boolean isNightMode() { DayNightMode dayNightMode = pref.get(); if (dayNightMode.isDay()) { return false; } else if (dayNightMode.isNight()) { return true; } else // We are in auto mode! if (dayNightMode.isAuto()) { long currentTime = System.currentTimeMillis(); // allow recalculation each 60 seconds if (currentTime - lastTime > 60000) { lastTime = System.currentTimeMillis(); try { SunriseSunset daynightSwitch = getSunriseSunset(); if (daynightSwitch != null) { boolean daytime = daynightSwitch.isDaytime(); log.debug("Sunrise/sunset setting to day: " + daytime); //$NON-NLS-1$ lastNightMode = !daytime; } } catch (IllegalArgumentException e) { log.warn("Network location provider not available"); //$NON-NLS-1$ } catch (SecurityException e) { log.warn("Missing permissions to get actual location!"); //$NON-NLS-1$ } } return lastNightMode; } else if (dayNightMode.isSensor()) { return lastNightMode; } return false; } public SunriseSunset getSunriseSunset() { Location lastKnownLocation = osmandApplication.getLocationProvider().getLastKnownLocation(); if(lastKnownLocation == null) { lastKnownLocation = osmandApplication.getLocationProvider().getFirstTimeRunDefaultLocation(); } if (lastKnownLocation == null) { return null; } double longitude = lastKnownLocation.getLongitude(); Date actualTime = new Date(); SunriseSunset daynightSwitch = new SunriseSunset(lastKnownLocation.getLatitude(), longitude < 0 ? 360 + longitude : longitude, actualTime, TimeZone.getDefault()); return daynightSwitch; } public void stopSensorIfNeeded() { if (listener != null) { SensorManager mSensorManager = (SensorManager) osmandApplication .getSystemService(Context.SENSOR_SERVICE); Sensor mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); mSensorManager.unregisterListener(listener, mLight); listener = null; } } public void startSensorIfNeeded(StateChangedListener<Boolean> sensorStateListener) { this.sensorStateListener = sensorStateListener; DayNightMode dayNightMode = pref.get(); if (listener == null && dayNightMode.isSensor()) { SensorManager mSensorManager = (SensorManager) osmandApplication.getSystemService(Context.SENSOR_SERVICE); Sensor mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); List<Sensor> list = mSensorManager.getSensorList(Sensor.TYPE_LIGHT); log.info("Light sensors:" + list.size()); //$NON-NLS-1$ mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); listener = this; } else if (listener != null && !dayNightMode.isSensor()) { stopSensorIfNeeded(); } } @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { // nothing to do here } @Override public void onSensorChanged(SensorEvent event) { if (event.values.length > 0) { float lux = event.values[0]; // log.debug("lux value:" + lux + " setting to day: " + (lux > SensorManager.LIGHT_CLOUDY)); //$NON-NLS-1$ //$NON-NLS-2$ boolean nightMode = lux > SensorManager.LIGHT_CLOUDY ? false : true; if (nightMode != lastNightMode) { if (System.currentTimeMillis() - lastTime > 10000) { lastTime = System.currentTimeMillis(); lastNightMode = nightMode; sensorStateListener.stateChanged(nightMode); } } } } }