diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/display/ColorTemperatureController.java b/lineage/lib/main/java/org/lineageos/platform/internal/display/ColorTemperatureController.java index 7dbd2874..67853a47 100644 --- a/lineage/lib/main/java/org/lineageos/platform/internal/display/ColorTemperatureController.java +++ b/lineage/lib/main/java/org/lineageos/platform/internal/display/ColorTemperatureController.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 The CyanogenMod Project + * Copyright (C) 2018 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +27,7 @@ import android.util.Range; import android.util.Slog; import android.view.animation.LinearInterpolator; -import org.lineageos.platform.internal.display.TwilightTracker.TwilightState; +import com.android.server.twilight.TwilightState; import java.io.PrintWriter; import java.util.BitSet; @@ -191,7 +192,15 @@ public class ColorTemperatureController extends LiveDisplayFeature { } else if (mode == MODE_NIGHT) { temperature = mNightTemperature; } else if (mode == MODE_AUTO) { - temperature = getTwilightK(); + final int twilightTemp = getTwilightK(); + if (twilightTemp >= 0) { + temperature = twilightTemp; + } else { + if (DEBUG) { + Slog.d(TAG, "updateColorTemperature: getTwilightK returned < 0; " + + "maintaining existing temperature"); + } + } } if (DEBUG) { @@ -203,6 +212,7 @@ public class ColorTemperatureController extends LiveDisplayFeature { if (isTransitioning()) { // fire again in a minute + mHandler.removeCallbacks(mTransitionRunnable); mHandler.postDelayed(mTransitionRunnable, DateUtils.MINUTE_IN_MILLIS); } } @@ -260,6 +270,10 @@ public class ColorTemperatureController extends LiveDisplayFeature { } private synchronized void setDisplayTemperature(int temperature) { + if (temperature < 0) { + // We're in not yet initialized state, silently ignore. + return; + } if (!mColorTemperatureRange.contains(temperature)) { Slog.e(TAG, "Color temperature out of range: " + temperature); return; @@ -282,50 +296,47 @@ public class ColorTemperatureController extends LiveDisplayFeature { } } - /** - * Where is the sun anyway? This calculation determines day or night, and scales - * the value around sunset/sunrise for a smooth transition. - * - * @param now - * @param sunset - * @param sunrise - * @return float between 0 and 1 - */ - private static float adj(long now, long sunset, long sunrise) { - if (sunset < 0 || sunrise < 0 - || now < sunset || now > (sunrise + TWILIGHT_ADJUSTMENT_TIME)) { - return 1.0f; - } - - if (now <= (sunset + TWILIGHT_ADJUSTMENT_TIME)) { - return MathUtils.lerp(1.0f, 0.0f, - (float) (now - sunset) / TWILIGHT_ADJUSTMENT_TIME); - } - - if (now >= sunrise) { - return MathUtils.lerp(1.0f, 0.0f, - (float) ((sunrise + TWILIGHT_ADJUSTMENT_TIME) - now) / TWILIGHT_ADJUSTMENT_TIME); - } - - return 0.0f; - } - /** * Determine the color temperature we should use for the display based on * the position of the sun. * - * @return color temperature in Kelvin + * @return color temperature in Kelvin or -1 if current state can't be determined. */ private int getTwilightK() { - float adjustment = 1.0f; final TwilightState twilight = getTwilight(); - - if (twilight != null) { - final long now = System.currentTimeMillis(); - adjustment = adj(now, twilight.getYesterdaySunset(), twilight.getTodaySunrise()) * - adj(now, twilight.getTodaySunset(), twilight.getTomorrowSunrise()); + if (twilight == null) { + return -1; } + final long now = System.currentTimeMillis(); + final long sunrise = twilight.sunriseTimeMillis(); + final long sunset = twilight.sunsetTimeMillis(); + final float adjustment; + + // Sanity checks + if (sunrise <= 0 || sunset <= 0) { + return -1; + } + + if (now >= sunrise && now < sunset) { + // It's daytime + if (now < sunrise + TWILIGHT_ADJUSTMENT_TIME) { + adjustment = MathUtils.lerp(0.0f, 1.0f, (float) (now - sunrise) / + TWILIGHT_ADJUSTMENT_TIME); + } else { + adjustment = 1.0f; + } + } else if (now >= sunset && now < sunrise) { + // It's nighttime + if (now < sunset + TWILIGHT_ADJUSTMENT_TIME) { + adjustment = MathUtils.lerp(1.0f, 0.0f, (float) (now - sunset) / + TWILIGHT_ADJUSTMENT_TIME); + } else { + adjustment = 0.0f; + } + } else { + return -1; + } return (int)MathUtils.lerp(mNightTemperature, mDayTemperature, adjustment); } diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayFeature.java b/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayFeature.java index d3279430..635183be 100644 --- a/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayFeature.java +++ b/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayFeature.java @@ -22,9 +22,10 @@ import android.os.Handler; import android.os.UserHandle; import android.util.Log; +import com.android.server.twilight.TwilightState; + import org.lineageos.platform.internal.common.UserContentObserver; import org.lineageos.platform.internal.display.LiveDisplayService.State; -import org.lineageos.platform.internal.display.TwilightTracker.TwilightState; import java.io.PrintWriter; import java.util.BitSet; diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayService.java b/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayService.java index bc8f2ec3..60e82d9d 100644 --- a/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayService.java +++ b/lineage/lib/main/java/org/lineageos/platform/internal/display/LiveDisplayService.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2016 The CyanogenMod Project + * Copyright (C) 2018 The LineageOS Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,11 +36,12 @@ import android.view.Display; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.power.BatterySaverPolicy.ServiceType; +import com.android.server.twilight.TwilightListener; +import com.android.server.twilight.TwilightManager; +import com.android.server.twilight.TwilightState; import org.lineageos.platform.internal.LineageSystemService; import org.lineageos.platform.internal.common.UserContentObserver; -import org.lineageos.platform.internal.display.TwilightTracker.TwilightListener; -import org.lineageos.platform.internal.display.TwilightTracker.TwilightState; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -81,7 +83,7 @@ public class LiveDisplayService extends LineageSystemService { private DisplayManager mDisplayManager; private ModeObserver mModeObserver; - private final TwilightTracker mTwilightTracker; + private TwilightManager mTwilightManager; private boolean mAwaitingNudge = true; private boolean mSunset = false; @@ -130,8 +132,6 @@ public class LiveDisplayService extends LineageSystemService { Process.THREAD_PRIORITY_DEFAULT, false /*allowIo*/); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); - - mTwilightTracker = new TwilightTracker(context); } @Override @@ -202,8 +202,9 @@ public class LiveDisplayService extends LineageSystemService { mState.mLowPowerMode = pmi.getLowPowerState(SERVICE_TYPE_DUMMY).globalBatterySaverEnabled; - mTwilightTracker.registerListener(mTwilightListener, mHandler); - mState.mTwilight = mTwilightTracker.getCurrentState(); + mTwilightManager = getLocalService(TwilightManager.class); + mTwilightManager.registerListener(mTwilightListener, mHandler); + mState.mTwilight = mTwilightManager.getLastTwilightState(); if (mConfig.hasModeSupport()) { mModeObserver = new ModeObserver(mHandler); @@ -373,7 +374,7 @@ public class LiveDisplayService extends LineageSystemService { @Override public boolean isNight() { - final TwilightState twilight = mTwilightTracker.getCurrentState(); + final TwilightState twilight = mTwilightManager.getLastTwilightState(); return twilight != null && twilight.isNight(); } }; @@ -465,8 +466,8 @@ public class LiveDisplayService extends LineageSystemService { // Night watchman private final TwilightListener mTwilightListener = new TwilightListener() { @Override - public void onTwilightStateChanged() { - mState.mTwilight = mTwilightTracker.getCurrentState(); + public void onTwilightStateChanged(TwilightState state) { + mState.mTwilight = state; updateFeatures(TWILIGHT_CHANGED); nudge(); } @@ -511,7 +512,7 @@ public class LiveDisplayService extends LineageSystemService { * @param state */ private void nudge() { - final TwilightState twilight = mTwilightTracker.getCurrentState(); + final TwilightState twilight = mTwilightManager.getLastTwilightState(); if (!mAwaitingNudge || twilight == null) { return; } diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightCalculator.java b/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightCalculator.java deleted file mode 100644 index 31c94c7b..00000000 --- a/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightCalculator.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.lineageos.platform.internal.display; - -import android.text.format.DateUtils; -import android.util.FloatMath; - -/** @hide */ -public class TwilightCalculator { - - /** Value of {@link #mState} if it is currently day */ - public static final int DAY = 0; - - /** Value of {@link #mState} if it is currently night */ - public static final int NIGHT = 1; - - private static final float DEGREES_TO_RADIANS = (float) (Math.PI / 180.0f); - - // element for calculating solar transit. - private static final float J0 = 0.0009f; - - // correction for civil twilight - private static final float ALTIDUTE_CORRECTION_CIVIL_TWILIGHT = -0.104719755f; - - // coefficients for calculating Equation of Center. - private static final float C1 = 0.0334196f; - private static final float C2 = 0.000349066f; - private static final float C3 = 0.000005236f; - - private static final float OBLIQUITY = 0.40927971f; - - // Java time on Jan 1, 2000 12:00 UTC. - private static final long UTC_2000 = 946728000000L; - - /** - * Time of sunset (civil twilight) in milliseconds or -1 in the case the day - * or night never ends. - */ - public long mSunset; - - /** - * Time of sunrise (civil twilight) in milliseconds or -1 in the case the - * day or night never ends. - */ - public long mSunrise; - - /** Current state */ - public int mState; - - /** - * calculates the civil twilight bases on time and geo-coordinates. - * - * @param time time in milliseconds. - * @param latiude latitude in degrees. - * @param longitude latitude in degrees. - */ - public void calculateTwilight(long time, double latiude, double longitude) { - final float daysSince2000 = (float) (time - UTC_2000) / DateUtils.DAY_IN_MILLIS; - - // mean anomaly - final float meanAnomaly = 6.240059968f + daysSince2000 * 0.01720197f; - - // true anomaly - final float trueAnomaly = meanAnomaly + C1 * FloatMath.sin(meanAnomaly) + C2 - * FloatMath.sin(2 * meanAnomaly) + C3 * FloatMath.sin(3 * meanAnomaly); - - // ecliptic longitude - final float solarLng = trueAnomaly + 1.796593063f + (float) Math.PI; - - // solar transit in days since 2000 - final double arcLongitude = -longitude / 360; - float n = Math.round(daysSince2000 - J0 - arcLongitude); - double solarTransitJ2000 = n + J0 + arcLongitude + 0.0053f * FloatMath.sin(meanAnomaly) - + -0.0069f * FloatMath.sin(2 * solarLng); - - // declination of sun - double solarDec = Math.asin(FloatMath.sin(solarLng) * FloatMath.sin(OBLIQUITY)); - - final double latRad = latiude * DEGREES_TO_RADIANS; - - double cosHourAngle = (FloatMath.sin(ALTIDUTE_CORRECTION_CIVIL_TWILIGHT) - Math.sin(latRad) - * Math.sin(solarDec)) / (Math.cos(latRad) * Math.cos(solarDec)); - // The day or night never ends for the given date and location, if this value is out of - // range. - if (cosHourAngle >= 1) { - mState = NIGHT; - mSunset = -1; - mSunrise = -1; - return; - } else if (cosHourAngle <= -1) { - mState = DAY; - mSunset = -1; - mSunrise = -1; - return; - } - - float hourAngle = (float) (Math.acos(cosHourAngle) / (2 * Math.PI)); - - mSunset = Math.round((solarTransitJ2000 + hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000; - mSunrise = Math.round((solarTransitJ2000 - hourAngle) * DateUtils.DAY_IN_MILLIS) + UTC_2000; - - if (mSunrise < time && mSunset > time) { - mState = DAY; - } else { - mState = NIGHT; - } - } - -} diff --git a/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightTracker.java b/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightTracker.java deleted file mode 100644 index e64f28d4..00000000 --- a/lineage/lib/main/java/org/lineageos/platform/internal/display/TwilightTracker.java +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.lineageos.platform.internal.display; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.location.Criteria; -import android.location.Location; -import android.location.LocationListener; -import android.location.LocationManager; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; -import android.text.format.DateUtils; -import android.text.format.Time; -import android.util.Slog; - -import java.text.DateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.Iterator; - -import libcore.util.Objects; - -/** - * Figures out whether it's twilight time based on the user's location. - * - * Used by the UI mode manager and other components to adjust night mode - * effects based on sunrise and sunset. - */ -public final class TwilightTracker { - private static final String TAG = "TwilightTracker"; - private static final boolean DEBUG = false; - private static final String ACTION_UPDATE_TWILIGHT_STATE = - "lineageos.platform.intent.action.UPDATE_TWILIGHT_STATE"; - - private final Object mLock = new Object(); - - private final AlarmManager mAlarmManager; - private final LocationManager mLocationManager; - private final LocationHandler mLocationHandler; - - private final ArrayList mListeners = - new ArrayList(); - - private TwilightState mTwilightState; - - private final Context mContext; - - public TwilightTracker(Context context) { - mContext = context; - mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); - mLocationManager = (LocationManager) mContext.getSystemService( - Context.LOCATION_SERVICE); - mLocationHandler = new LocationHandler(); - - IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); - filter.addAction(Intent.ACTION_TIME_CHANGED); - filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); - filter.addAction(ACTION_UPDATE_TWILIGHT_STATE); - mContext.registerReceiver(mUpdateLocationReceiver, filter); - } - - /** - * Gets the current twilight state. - * - * @return The current twilight state, or null if no information is available. - */ - public TwilightState getCurrentState() { - synchronized (mLock) { - return mTwilightState; - } - } - - /** - * Listens for twilight time. - * - * @param listener The listener. - */ - public void registerListener(TwilightListener listener, Handler handler) { - synchronized (mLock) { - mListeners.add(new TwilightListenerRecord(listener, handler)); - - if (mListeners.size() == 1) { - mLocationHandler.enableLocationUpdates(); - } - } - } - - - private void setTwilightState(TwilightState state) { - synchronized (mLock) { - if (!Objects.equal(mTwilightState, state)) { - if (DEBUG) { - Slog.d(TAG, "Twilight state changed: " + state); - } - - mTwilightState = state; - - final int listenerLen = mListeners.size(); - for (int i = 0; i < listenerLen; i++) { - mListeners.get(i).postUpdate(); - } - } - } - } - - // The user has moved if the accuracy circles of the two locations don't overlap. - private static boolean hasMoved(Location from, Location to) { - if (to == null) { - return false; - } - - if (from == null) { - return true; - } - - // if new location is older than the current one, the device hasn't moved. - if (to.getElapsedRealtimeNanos() < from.getElapsedRealtimeNanos()) { - return false; - } - - // Get the distance between the two points. - float distance = from.distanceTo(to); - - // Get the total accuracy radius for both locations. - float totalAccuracy = from.getAccuracy() + to.getAccuracy(); - - // If the distance is greater than the combined accuracy of the two - // points then they can't overlap and hence the user has moved. - return distance >= totalAccuracy; - } - - private final class LocationHandler extends Handler { - private static final int MSG_ENABLE_LOCATION_UPDATES = 1; - private static final int MSG_GET_NEW_LOCATION_UPDATE = 2; - private static final int MSG_PROCESS_NEW_LOCATION = 3; - private static final int MSG_DO_TWILIGHT_UPDATE = 4; - - private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS; - private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; - private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; - private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = - 15 * DateUtils.MINUTE_IN_MILLIS; - private static final double FACTOR_GMT_OFFSET_LONGITUDE = - 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; - - private boolean mPassiveListenerEnabled; - private boolean mNetworkListenerEnabled; - private boolean mDidFirstInit; - private long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS; - private long mLastUpdateInterval; - private Location mLocation; - private final TwilightCalculator mTwilightCalculator = new TwilightCalculator(); - - public void processNewLocation(Location location) { - Message msg = obtainMessage(MSG_PROCESS_NEW_LOCATION, location); - sendMessage(msg); - } - - public void enableLocationUpdates() { - sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); - } - - public void requestLocationUpdate() { - sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE); - } - - public void requestTwilightUpdate() { - sendEmptyMessage(MSG_DO_TWILIGHT_UPDATE); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_PROCESS_NEW_LOCATION: { - final Location location = (Location) msg.obj; - final boolean hasMoved = hasMoved(mLocation, location); - final boolean hasBetterAccuracy = mLocation == null - || location.getAccuracy() < mLocation.getAccuracy(); - if (DEBUG) { - Slog.d(TAG, "Processing new location: " + location - + ", hasMoved=" + hasMoved - + ", hasBetterAccuracy=" + hasBetterAccuracy); - } - if (hasMoved || hasBetterAccuracy) { - setLocation(location); - } - break; - } - - case MSG_GET_NEW_LOCATION_UPDATE: - if (!mNetworkListenerEnabled) { - // Don't do anything -- we are still trying to get a - // location. - return; - } - if ((mLastNetworkRegisterTime + MIN_LOCATION_UPDATE_MS) >= - SystemClock.elapsedRealtime()) { - // Don't do anything -- it hasn't been long enough - // since we last requested an update. - return; - } - - // Unregister the current location monitor, so we can - // register a new one for it to get an immediate update. - mNetworkListenerEnabled = false; - mLocationManager.removeUpdates(mEmptyLocationListener); - - // Fall through to re-register listener. - case MSG_ENABLE_LOCATION_UPDATES: - // enable network provider to receive at least location updates for a given - // distance. - boolean networkLocationEnabled; - try { - networkLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if network location provider - // does not exist or is not yet installed. - networkLocationEnabled = false; - } - if (!mNetworkListenerEnabled && networkLocationEnabled) { - mNetworkListenerEnabled = true; - mLastNetworkRegisterTime = SystemClock.elapsedRealtime(); - mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, - LOCATION_UPDATE_MS, 0, mEmptyLocationListener); - - if (!mDidFirstInit) { - mDidFirstInit = true; - if (mLocation == null) { - retrieveLocation(); - } - } - } - - // enable passive provider to receive updates from location fixes (gps - // and network). - boolean passiveLocationEnabled; - try { - passiveLocationEnabled = - mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); - } catch (Exception e) { - // we may get IllegalArgumentException if passive location provider - // does not exist or is not yet installed. - passiveLocationEnabled = false; - } - - if (!mPassiveListenerEnabled && passiveLocationEnabled) { - mPassiveListenerEnabled = true; - mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, - 0, LOCATION_UPDATE_DISTANCE_METER, mLocationListener); - } - - if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { - mLastUpdateInterval *= 1.5; - if (mLastUpdateInterval == 0) { - mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; - } else if (mLastUpdateInterval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { - mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; - } - sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval); - } - - if (!networkLocationEnabled && mLocation == null) { - if (DEBUG) { - Slog.d(TAG, "Network location unavailable"); - } - retrieveLocation(); - } - break; - - case MSG_DO_TWILIGHT_UPDATE: - updateTwilightState(); - break; - } - } - - private void retrieveLocation() { - Location location = null; - final Iterator providers = - mLocationManager.getProviders(new Criteria(), true).iterator(); - while (providers.hasNext()) { - final Location lastKnownLocation = - mLocationManager.getLastKnownLocation(providers.next()); - // pick the most recent location - if (location == null || (lastKnownLocation != null && - location.getElapsedRealtimeNanos() < - lastKnownLocation.getElapsedRealtimeNanos())) { - location = lastKnownLocation; - } - } - - // In the case there is no location available (e.g. GPS fix or network location - // is not available yet), the longitude of the location is estimated using the timezone, - // latitude and accuracy are set to get a good average. - if (location == null) { - Time currentTime = new Time(); - currentTime.set(System.currentTimeMillis()); - double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * - (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); - location = new Location("fake"); - location.setLongitude(lngOffset); - location.setLatitude(0); - location.setAccuracy(417000.0f); - location.setTime(System.currentTimeMillis()); - location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); - - if (DEBUG) { - Slog.d(TAG, "Estimated location from timezone: " + location); - } - } - - setLocation(location); - } - - private void setLocation(Location location) { - mLocation = location; - updateTwilightState(); - } - - private void updateTwilightState() { - if (mLocation == null) { - setTwilightState(null); - return; - } - - final long now = System.currentTimeMillis(); - - // calculate yesterday's twilight - mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS, - mLocation.getLatitude(), mLocation.getLongitude()); - final long yesterdaySunset = mTwilightCalculator.mSunset; - - // calculate today's twilight - mTwilightCalculator.calculateTwilight(now, - mLocation.getLatitude(), mLocation.getLongitude()); - final boolean isNight = (mTwilightCalculator.mState == TwilightCalculator.NIGHT); - final long todaySunrise = mTwilightCalculator.mSunrise; - final long todaySunset = mTwilightCalculator.mSunset; - - // calculate tomorrow's twilight - mTwilightCalculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS, - mLocation.getLatitude(), mLocation.getLongitude()); - final long tomorrowSunrise = mTwilightCalculator.mSunrise; - - // set twilight state - TwilightState state = new TwilightState(isNight, yesterdaySunset, - todaySunrise, todaySunset, tomorrowSunrise); - if (DEBUG) { - Slog.d(TAG, "Updating twilight state: " + state); - } - setTwilightState(state); - - // schedule next update - long nextUpdate = 0; - if (todaySunrise == -1 || todaySunset == -1) { - // In the case the day or night never ends the update is scheduled 12 hours later. - nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS; - } else { - // add some extra time to be on the safe side. - nextUpdate += DateUtils.MINUTE_IN_MILLIS; - - if (now > todaySunset) { - nextUpdate += tomorrowSunrise; - } else if (now > todaySunrise) { - nextUpdate += todaySunset; - } else { - nextUpdate += todaySunrise; - } - } - - if (DEBUG) { - Slog.d(TAG, "Next update in " + (nextUpdate - now) + " ms"); - } - - Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE); - PendingIntent pendingIntent = PendingIntent.getBroadcast( - mContext, 0, updateIntent, 0); - mAlarmManager.cancel(pendingIntent); - mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent); - } - } - - private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction()) - && !intent.getBooleanExtra("state", false)) { - // Airplane mode is now off! - mLocationHandler.requestLocationUpdate(); - return; - } - - // Time zone has changed or alarm expired. - mLocationHandler.requestTwilightUpdate(); - } - }; - - // A LocationListener to initialize the network location provider. The location updates - // are handled through the passive location provider. - private final LocationListener mEmptyLocationListener = new LocationListener() { - public void onLocationChanged(Location location) { - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - - private final LocationListener mLocationListener = new LocationListener() { - public void onLocationChanged(Location location) { - mLocationHandler.processNewLocation(location); - } - - public void onProviderDisabled(String provider) { - } - - public void onProviderEnabled(String provider) { - } - - public void onStatusChanged(String provider, int status, Bundle extras) { - } - }; - - public static class TwilightState { - private final boolean mIsNight; - private final long mYesterdaySunset; - private final long mTodaySunrise; - private final long mTodaySunset; - private final long mTomorrowSunrise; - - TwilightState(boolean isNight, - long yesterdaySunset, - long todaySunrise, long todaySunset, - long tomorrowSunrise) { - mIsNight = isNight; - mYesterdaySunset = yesterdaySunset; - mTodaySunrise = todaySunrise; - mTodaySunset = todaySunset; - mTomorrowSunrise = tomorrowSunrise; - } - - /** - * Returns true if it is currently night time. - */ - public boolean isNight() { - return mIsNight; - } - - /** - * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase, - * or -1 if the sun never sets. - */ - public long getYesterdaySunset() { - return mYesterdaySunset; - } - - /** - * Returns the time of today's sunrise in the System.currentTimeMillis() timebase, - * or -1 if the sun never rises. - */ - public long getTodaySunrise() { - return mTodaySunrise; - } - - /** - * Returns the time of today's sunset in the System.currentTimeMillis() timebase, - * or -1 if the sun never sets. - */ - public long getTodaySunset() { - return mTodaySunset; - } - - /** - * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase, - * or -1 if the sun never rises. - */ - public long getTomorrowSunrise() { - return mTomorrowSunrise; - } - - @Override - public boolean equals(Object o) { - return o instanceof TwilightState && equals((TwilightState) o); - } - - public boolean equals(TwilightState other) { - return other != null - && mIsNight == other.mIsNight - && mYesterdaySunset == other.mYesterdaySunset - && mTodaySunrise == other.mTodaySunrise - && mTodaySunset == other.mTodaySunset - && mTomorrowSunrise == other.mTomorrowSunrise; - } - - @Override - public int hashCode() { - return 0; // don't care - } - - @Override - public String toString() { - DateFormat f = DateFormat.getDateTimeInstance(); - return "{TwilightState: isNight=" + mIsNight - + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset)) - + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise)) - + ", mTodaySunset=" + f.format(new Date(mTodaySunset)) - + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise)) - + "}"; - - } - } - - public interface TwilightListener { - void onTwilightStateChanged(); - } - - private static class TwilightListenerRecord implements Runnable { - private final TwilightListener mListener; - private final Handler mHandler; - - public TwilightListenerRecord(TwilightListener listener, Handler handler) { - mListener = listener; - mHandler = handler; - } - - public void postUpdate() { - mHandler.post(this); - } - - @Override - public void run() { - mListener.onTwilightStateChanged(); - } - } -}