12416e09649eb6ab767eba458796e126196c77a34Jeff Brown/* 22416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Copyright (C) 2012 The Android Open Source Project 32416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 42416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 52416e09649eb6ab767eba458796e126196c77a34Jeff Brown * you may not use this file except in compliance with the License. 62416e09649eb6ab767eba458796e126196c77a34Jeff Brown * You may obtain a copy of the License at 72416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 82416e09649eb6ab767eba458796e126196c77a34Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 92416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 102416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Unless required by applicable law or agreed to in writing, software 112416e09649eb6ab767eba458796e126196c77a34Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 122416e09649eb6ab767eba458796e126196c77a34Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132416e09649eb6ab767eba458796e126196c77a34Jeff Brown * See the License for the specific language governing permissions and 142416e09649eb6ab767eba458796e126196c77a34Jeff Brown * limitations under the License. 152416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 162416e09649eb6ab767eba458796e126196c77a34Jeff Brown 172416e09649eb6ab767eba458796e126196c77a34Jeff Brownpackage com.android.server; 182416e09649eb6ab767eba458796e126196c77a34Jeff Brown 192416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.app.AlarmManager; 202416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.app.PendingIntent; 212416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.BroadcastReceiver; 222416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.Context; 232416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.Intent; 242416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.IntentFilter; 252416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.Criteria; 262416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.Location; 272416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.LocationListener; 282416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.LocationManager; 292416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Bundle; 302416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Handler; 312416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Message; 322416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.SystemClock; 332416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.text.format.DateUtils; 342416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.text.format.Time; 352416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.util.Slog; 362416e09649eb6ab767eba458796e126196c77a34Jeff Brown 372416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.text.DateFormat; 382416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.util.ArrayList; 392416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.util.Date; 402416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.util.Iterator; 412416e09649eb6ab767eba458796e126196c77a34Jeff Brown 422416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport libcore.util.Objects; 432416e09649eb6ab767eba458796e126196c77a34Jeff Brown 442416e09649eb6ab767eba458796e126196c77a34Jeff Brown/** 452416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Figures out whether it's twilight time based on the user's location. 462416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 472416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Used by the UI mode manager and other components to adjust night mode 482416e09649eb6ab767eba458796e126196c77a34Jeff Brown * effects based on sunrise and sunset. 492416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 502416e09649eb6ab767eba458796e126196c77a34Jeff Brownpublic final class TwilightService { 512416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final String TAG = "TwilightService"; 522416e09649eb6ab767eba458796e126196c77a34Jeff Brown 53b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown private static final boolean DEBUG = false; 542416e09649eb6ab767eba458796e126196c77a34Jeff Brown 552416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final String ACTION_UPDATE_TWILIGHT_STATE = 562416e09649eb6ab767eba458796e126196c77a34Jeff Brown "com.android.server.action.UPDATE_TWILIGHT_STATE"; 572416e09649eb6ab767eba458796e126196c77a34Jeff Brown 582416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final Context mContext; 592416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final AlarmManager mAlarmManager; 602416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationManager mLocationManager; 612416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationHandler mLocationHandler; 622416e09649eb6ab767eba458796e126196c77a34Jeff Brown 632416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final Object mLock = new Object(); 642416e09649eb6ab767eba458796e126196c77a34Jeff Brown 652416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final ArrayList<TwilightListenerRecord> mListeners = 662416e09649eb6ab767eba458796e126196c77a34Jeff Brown new ArrayList<TwilightListenerRecord>(); 672416e09649eb6ab767eba458796e126196c77a34Jeff Brown 682416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mSystemReady; 692416e09649eb6ab767eba458796e126196c77a34Jeff Brown 702416e09649eb6ab767eba458796e126196c77a34Jeff Brown private TwilightState mTwilightState; 712416e09649eb6ab767eba458796e126196c77a34Jeff Brown 722416e09649eb6ab767eba458796e126196c77a34Jeff Brown public TwilightService(Context context) { 732416e09649eb6ab767eba458796e126196c77a34Jeff Brown mContext = context; 742416e09649eb6ab767eba458796e126196c77a34Jeff Brown 752416e09649eb6ab767eba458796e126196c77a34Jeff Brown mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); 762416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager = (LocationManager)mContext.getSystemService(Context.LOCATION_SERVICE); 772416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler = new LocationHandler(); 782416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 792416e09649eb6ab767eba458796e126196c77a34Jeff Brown 802416e09649eb6ab767eba458796e126196c77a34Jeff Brown void systemReady() { 812416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 822416e09649eb6ab767eba458796e126196c77a34Jeff Brown mSystemReady = true; 832416e09649eb6ab767eba458796e126196c77a34Jeff Brown 842416e09649eb6ab767eba458796e126196c77a34Jeff Brown IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 852416e09649eb6ab767eba458796e126196c77a34Jeff Brown filter.addAction(Intent.ACTION_TIME_CHANGED); 862416e09649eb6ab767eba458796e126196c77a34Jeff Brown filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 872416e09649eb6ab767eba458796e126196c77a34Jeff Brown filter.addAction(ACTION_UPDATE_TWILIGHT_STATE); 882416e09649eb6ab767eba458796e126196c77a34Jeff Brown mContext.registerReceiver(mUpdateLocationReceiver, filter); 892416e09649eb6ab767eba458796e126196c77a34Jeff Brown 902416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mListeners.isEmpty()) { 912416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.enableLocationUpdates(); 922416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 932416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 942416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 952416e09649eb6ab767eba458796e126196c77a34Jeff Brown 962416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 972416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Gets the current twilight state. 982416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 992416e09649eb6ab767eba458796e126196c77a34Jeff Brown * @return The current twilight state, or null if no information is available. 1002416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 1012416e09649eb6ab767eba458796e126196c77a34Jeff Brown public TwilightState getCurrentState() { 1022416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 1032416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mTwilightState; 1042416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1052416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1062416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1072416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 1082416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Listens for twilight time. 1092416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 1102416e09649eb6ab767eba458796e126196c77a34Jeff Brown * @param listener The listener. 1112416e09649eb6ab767eba458796e126196c77a34Jeff Brown * @param handler The handler on which to post calls into the listener. 1122416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 1132416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void registerListener(TwilightListener listener, Handler handler) { 1142416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 1152416e09649eb6ab767eba458796e126196c77a34Jeff Brown mListeners.add(new TwilightListenerRecord(listener, handler)); 1162416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1172416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (mSystemReady && mListeners.size() == 1) { 1182416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.enableLocationUpdates(); 1192416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1202416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1212416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1222416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1232416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void setTwilightState(TwilightState state) { 1242416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 1252416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!Objects.equal(mTwilightState, state)) { 1262416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 1272416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Twilight state changed: " + state); 1282416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1292416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1302416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightState = state; 1312416e09649eb6ab767eba458796e126196c77a34Jeff Brown int count = mListeners.size(); 1322416e09649eb6ab767eba458796e126196c77a34Jeff Brown for (int i = 0; i < count; i++) { 1332416e09649eb6ab767eba458796e126196c77a34Jeff Brown mListeners.get(i).post(); 1342416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1352416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1362416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1372416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1382416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1392416e09649eb6ab767eba458796e126196c77a34Jeff Brown // The user has moved if the accuracy circles of the two locations don't overlap. 1402416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static boolean hasMoved(Location from, Location to) { 1412416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (to == null) { 1422416e09649eb6ab767eba458796e126196c77a34Jeff Brown return false; 1432416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1442416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1452416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (from == null) { 1462416e09649eb6ab767eba458796e126196c77a34Jeff Brown return true; 1472416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1482416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1492416e09649eb6ab767eba458796e126196c77a34Jeff Brown // if new location is older than the current one, the device hasn't moved. 1504118012da9a22694b3353040a485f8cdc27e2f17Philip Milne if (to.getElapsedRealtimeNanos() < from.getElapsedRealtimeNanos()) { 1512416e09649eb6ab767eba458796e126196c77a34Jeff Brown return false; 1522416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1532416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1542416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Get the distance between the two points. 1552416e09649eb6ab767eba458796e126196c77a34Jeff Brown float distance = from.distanceTo(to); 1562416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1572416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Get the total accuracy radius for both locations. 1582416e09649eb6ab767eba458796e126196c77a34Jeff Brown float totalAccuracy = from.getAccuracy() + to.getAccuracy(); 1592416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1602416e09649eb6ab767eba458796e126196c77a34Jeff Brown // If the distance is greater than the combined accuracy of the two 1612416e09649eb6ab767eba458796e126196c77a34Jeff Brown // points then they can't overlap and hence the user has moved. 1622416e09649eb6ab767eba458796e126196c77a34Jeff Brown return distance >= totalAccuracy; 1632416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1642416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1652416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 1662416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Describes whether it is day or night. 1672416e09649eb6ab767eba458796e126196c77a34Jeff Brown * This object is immutable. 1682416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 1692416e09649eb6ab767eba458796e126196c77a34Jeff Brown public static final class TwilightState { 1702416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final boolean mIsNight; 1712416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final long mYesterdaySunset; 1722416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final long mTodaySunrise; 1732416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final long mTodaySunset; 1742416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final long mTomorrowSunrise; 1752416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1762416e09649eb6ab767eba458796e126196c77a34Jeff Brown TwilightState(boolean isNight, 1772416e09649eb6ab767eba458796e126196c77a34Jeff Brown long yesterdaySunset, 1782416e09649eb6ab767eba458796e126196c77a34Jeff Brown long todaySunrise, long todaySunset, 1792416e09649eb6ab767eba458796e126196c77a34Jeff Brown long tomorrowSunrise) { 1802416e09649eb6ab767eba458796e126196c77a34Jeff Brown mIsNight = isNight; 1812416e09649eb6ab767eba458796e126196c77a34Jeff Brown mYesterdaySunset = yesterdaySunset; 1822416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTodaySunrise = todaySunrise; 1832416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTodaySunset = todaySunset; 1842416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTomorrowSunrise = tomorrowSunrise; 1852416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1862416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1872416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 1882416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Returns true if it is currently night time. 1892416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 1902416e09649eb6ab767eba458796e126196c77a34Jeff Brown public boolean isNight() { 1912416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mIsNight; 1922416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1932416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1942416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 1952416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Returns the time of yesterday's sunset in the System.currentTimeMillis() timebase, 1962416e09649eb6ab767eba458796e126196c77a34Jeff Brown * or -1 if the sun never sets. 1972416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 1982416e09649eb6ab767eba458796e126196c77a34Jeff Brown public long getYesterdaySunset() { 1992416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mYesterdaySunset; 2002416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2012416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2022416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 2032416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Returns the time of today's sunrise in the System.currentTimeMillis() timebase, 2042416e09649eb6ab767eba458796e126196c77a34Jeff Brown * or -1 if the sun never rises. 2052416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 2062416e09649eb6ab767eba458796e126196c77a34Jeff Brown public long getTodaySunrise() { 2072416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mTodaySunrise; 2082416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2092416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2102416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 2112416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Returns the time of today's sunset in the System.currentTimeMillis() timebase, 2122416e09649eb6ab767eba458796e126196c77a34Jeff Brown * or -1 if the sun never sets. 2132416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 2142416e09649eb6ab767eba458796e126196c77a34Jeff Brown public long getTodaySunset() { 2152416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mTodaySunset; 2162416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2172416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2182416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 2192416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Returns the time of tomorrow's sunrise in the System.currentTimeMillis() timebase, 2202416e09649eb6ab767eba458796e126196c77a34Jeff Brown * or -1 if the sun never rises. 2212416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 2222416e09649eb6ab767eba458796e126196c77a34Jeff Brown public long getTomorrowSunrise() { 2232416e09649eb6ab767eba458796e126196c77a34Jeff Brown return mTomorrowSunrise; 2242416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2252416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2262416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 2272416e09649eb6ab767eba458796e126196c77a34Jeff Brown public boolean equals(Object o) { 2282416e09649eb6ab767eba458796e126196c77a34Jeff Brown return o instanceof TwilightState && equals((TwilightState)o); 2292416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2302416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2312416e09649eb6ab767eba458796e126196c77a34Jeff Brown public boolean equals(TwilightState other) { 2322416e09649eb6ab767eba458796e126196c77a34Jeff Brown return other != null 2332416e09649eb6ab767eba458796e126196c77a34Jeff Brown && mIsNight == other.mIsNight 2342416e09649eb6ab767eba458796e126196c77a34Jeff Brown && mYesterdaySunset == other.mYesterdaySunset 2352416e09649eb6ab767eba458796e126196c77a34Jeff Brown && mTodaySunrise == other.mTodaySunrise 2362416e09649eb6ab767eba458796e126196c77a34Jeff Brown && mTodaySunset == other.mTodaySunset 2372416e09649eb6ab767eba458796e126196c77a34Jeff Brown && mTomorrowSunrise == other.mTomorrowSunrise; 2382416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2392416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2402416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 2412416e09649eb6ab767eba458796e126196c77a34Jeff Brown public int hashCode() { 2422416e09649eb6ab767eba458796e126196c77a34Jeff Brown return 0; // don't care 2432416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2442416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2452416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 2462416e09649eb6ab767eba458796e126196c77a34Jeff Brown public String toString() { 2472416e09649eb6ab767eba458796e126196c77a34Jeff Brown DateFormat f = DateFormat.getDateTimeInstance(); 2482416e09649eb6ab767eba458796e126196c77a34Jeff Brown return "{TwilightState: isNight=" + mIsNight 2492416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", mYesterdaySunset=" + f.format(new Date(mYesterdaySunset)) 2502416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", mTodaySunrise=" + f.format(new Date(mTodaySunrise)) 2512416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", mTodaySunset=" + f.format(new Date(mTodaySunset)) 2522416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", mTomorrowSunrise=" + f.format(new Date(mTomorrowSunrise)) 2532416e09649eb6ab767eba458796e126196c77a34Jeff Brown + "}"; 2542416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2552416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2562416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2572416e09649eb6ab767eba458796e126196c77a34Jeff Brown /** 2582416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Listener for changes in twilight state. 2592416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 2602416e09649eb6ab767eba458796e126196c77a34Jeff Brown public interface TwilightListener { 2612416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onTwilightStateChanged(); 2622416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2632416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2642416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final class TwilightListenerRecord implements Runnable { 2652416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final TwilightListener mListener; 2662416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final Handler mHandler; 2672416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2682416e09649eb6ab767eba458796e126196c77a34Jeff Brown public TwilightListenerRecord(TwilightListener listener, Handler handler) { 2692416e09649eb6ab767eba458796e126196c77a34Jeff Brown mListener = listener; 2702416e09649eb6ab767eba458796e126196c77a34Jeff Brown mHandler = handler; 2712416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2722416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2732416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void post() { 2742416e09649eb6ab767eba458796e126196c77a34Jeff Brown mHandler.post(this); 2752416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2762416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2772416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 2782416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void run() { 2792416e09649eb6ab767eba458796e126196c77a34Jeff Brown mListener.onTwilightStateChanged(); 2802416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2812416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2822416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2832416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final class LocationHandler extends Handler { 2842416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_ENABLE_LOCATION_UPDATES = 1; 2852416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_GET_NEW_LOCATION_UPDATE = 2; 2862416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_PROCESS_NEW_LOCATION = 3; 2872416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_DO_TWILIGHT_UPDATE = 4; 2882416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2892416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS; 2902416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; 2912416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; 2922416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; 2932416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 2942416e09649eb6ab767eba458796e126196c77a34Jeff Brown 15 * DateUtils.MINUTE_IN_MILLIS; 2952416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final double FACTOR_GMT_OFFSET_LONGITUDE = 2962416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; 2972416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2982416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mPassiveListenerEnabled; 2992416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mNetworkListenerEnabled; 3002416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mDidFirstInit; 3012416e09649eb6ab767eba458796e126196c77a34Jeff Brown private long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS; 3022416e09649eb6ab767eba458796e126196c77a34Jeff Brown private long mLastUpdateInterval; 3032416e09649eb6ab767eba458796e126196c77a34Jeff Brown private Location mLocation; 3042416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final TwilightCalculator mTwilightCalculator = new TwilightCalculator(); 3052416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3062416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void processNewLocation(Location location) { 3072416e09649eb6ab767eba458796e126196c77a34Jeff Brown Message msg = obtainMessage(MSG_PROCESS_NEW_LOCATION, location); 3082416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendMessage(msg); 3092416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3102416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3112416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void enableLocationUpdates() { 3122416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); 3132416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3142416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3152416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void requestLocationUpdate() { 3162416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE); 3172416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3182416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3192416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void requestTwilightUpdate() { 3202416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_DO_TWILIGHT_UPDATE); 3212416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3222416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3232416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 3242416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void handleMessage(Message msg) { 3252416e09649eb6ab767eba458796e126196c77a34Jeff Brown switch (msg.what) { 3262416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_PROCESS_NEW_LOCATION: { 3272416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Location location = (Location)msg.obj; 3282416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean hasMoved = hasMoved(mLocation, location); 3292416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean hasBetterAccuracy = mLocation == null 3302416e09649eb6ab767eba458796e126196c77a34Jeff Brown || location.getAccuracy() < mLocation.getAccuracy(); 3312416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 3322416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Processing new location: " + location 3332416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", hasMoved=" + hasMoved 3342416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", hasBetterAccuracy=" + hasBetterAccuracy); 3352416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3362416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (hasMoved || hasBetterAccuracy) { 3372416e09649eb6ab767eba458796e126196c77a34Jeff Brown setLocation(location); 3382416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3392416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 3402416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3412416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3422416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_GET_NEW_LOCATION_UPDATE: 3432416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mNetworkListenerEnabled) { 3442416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Don't do anything -- we are still trying to get a 3452416e09649eb6ab767eba458796e126196c77a34Jeff Brown // location. 3462416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 3472416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3482416e09649eb6ab767eba458796e126196c77a34Jeff Brown if ((mLastNetworkRegisterTime + MIN_LOCATION_UPDATE_MS) >= 3492416e09649eb6ab767eba458796e126196c77a34Jeff Brown SystemClock.elapsedRealtime()) { 3502416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Don't do anything -- it hasn't been long enough 3512416e09649eb6ab767eba458796e126196c77a34Jeff Brown // since we last requested an update. 3522416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 3532416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3542416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3552416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Unregister the current location monitor, so we can 3562416e09649eb6ab767eba458796e126196c77a34Jeff Brown // register a new one for it to get an immediate update. 3572416e09649eb6ab767eba458796e126196c77a34Jeff Brown mNetworkListenerEnabled = false; 3582416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.removeUpdates(mEmptyLocationListener); 3592416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3602416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Fall through to re-register listener. 3612416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_ENABLE_LOCATION_UPDATES: 3622416e09649eb6ab767eba458796e126196c77a34Jeff Brown // enable network provider to receive at least location updates for a given 3632416e09649eb6ab767eba458796e126196c77a34Jeff Brown // distance. 3642416e09649eb6ab767eba458796e126196c77a34Jeff Brown boolean networkLocationEnabled; 3652416e09649eb6ab767eba458796e126196c77a34Jeff Brown try { 3662416e09649eb6ab767eba458796e126196c77a34Jeff Brown networkLocationEnabled = 3672416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 3682416e09649eb6ab767eba458796e126196c77a34Jeff Brown } catch (Exception e) { 3692416e09649eb6ab767eba458796e126196c77a34Jeff Brown // we may get IllegalArgumentException if network location provider 3702416e09649eb6ab767eba458796e126196c77a34Jeff Brown // does not exist or is not yet installed. 3712416e09649eb6ab767eba458796e126196c77a34Jeff Brown networkLocationEnabled = false; 3722416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3732416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mNetworkListenerEnabled && networkLocationEnabled) { 3742416e09649eb6ab767eba458796e126196c77a34Jeff Brown mNetworkListenerEnabled = true; 3752416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastNetworkRegisterTime = SystemClock.elapsedRealtime(); 3762416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 3772416e09649eb6ab767eba458796e126196c77a34Jeff Brown LOCATION_UPDATE_MS, 0, mEmptyLocationListener); 3782416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3792416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mDidFirstInit) { 3802416e09649eb6ab767eba458796e126196c77a34Jeff Brown mDidFirstInit = true; 3812416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (mLocation == null) { 3822416e09649eb6ab767eba458796e126196c77a34Jeff Brown retrieveLocation(); 3832416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3842416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3852416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3862416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3872416e09649eb6ab767eba458796e126196c77a34Jeff Brown // enable passive provider to receive updates from location fixes (gps 3882416e09649eb6ab767eba458796e126196c77a34Jeff Brown // and network). 3892416e09649eb6ab767eba458796e126196c77a34Jeff Brown boolean passiveLocationEnabled; 3902416e09649eb6ab767eba458796e126196c77a34Jeff Brown try { 3912416e09649eb6ab767eba458796e126196c77a34Jeff Brown passiveLocationEnabled = 3922416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); 3932416e09649eb6ab767eba458796e126196c77a34Jeff Brown } catch (Exception e) { 3942416e09649eb6ab767eba458796e126196c77a34Jeff Brown // we may get IllegalArgumentException if passive location provider 3952416e09649eb6ab767eba458796e126196c77a34Jeff Brown // does not exist or is not yet installed. 3962416e09649eb6ab767eba458796e126196c77a34Jeff Brown passiveLocationEnabled = false; 3972416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3982416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3992416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mPassiveListenerEnabled && passiveLocationEnabled) { 4002416e09649eb6ab767eba458796e126196c77a34Jeff Brown mPassiveListenerEnabled = true; 4012416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 4022416e09649eb6ab767eba458796e126196c77a34Jeff Brown 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); 4032416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4042416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4052416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { 4062416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval *= 1.5; 4072416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (mLastUpdateInterval == 0) { 4082416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; 4092416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else if (mLastUpdateInterval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { 4102416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; 4112416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4122416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval); 4132416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4142416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 4152416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4162416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_DO_TWILIGHT_UPDATE: 4172416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateTwilightState(); 4182416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 4192416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4202416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4212416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4222416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void retrieveLocation() { 4232416e09649eb6ab767eba458796e126196c77a34Jeff Brown Location location = null; 4242416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Iterator<String> providers = 4252416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.getProviders(new Criteria(), true).iterator(); 4262416e09649eb6ab767eba458796e126196c77a34Jeff Brown while (providers.hasNext()) { 4272416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Location lastKnownLocation = 4282416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.getLastKnownLocation(providers.next()); 4292416e09649eb6ab767eba458796e126196c77a34Jeff Brown // pick the most recent location 4302416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (location == null || (lastKnownLocation != null && 4314118012da9a22694b3353040a485f8cdc27e2f17Philip Milne location.getElapsedRealtimeNanos() < 4324118012da9a22694b3353040a485f8cdc27e2f17Philip Milne lastKnownLocation.getElapsedRealtimeNanos())) { 4332416e09649eb6ab767eba458796e126196c77a34Jeff Brown location = lastKnownLocation; 4342416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4352416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4362416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4372416e09649eb6ab767eba458796e126196c77a34Jeff Brown // In the case there is no location available (e.g. GPS fix or network location 4382416e09649eb6ab767eba458796e126196c77a34Jeff Brown // is not available yet), the longitude of the location is estimated using the timezone, 4392416e09649eb6ab767eba458796e126196c77a34Jeff Brown // latitude and accuracy are set to get a good average. 4402416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (location == null) { 4412416e09649eb6ab767eba458796e126196c77a34Jeff Brown Time currentTime = new Time(); 4422416e09649eb6ab767eba458796e126196c77a34Jeff Brown currentTime.set(System.currentTimeMillis()); 4432416e09649eb6ab767eba458796e126196c77a34Jeff Brown double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * 4442416e09649eb6ab767eba458796e126196c77a34Jeff Brown (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); 4452416e09649eb6ab767eba458796e126196c77a34Jeff Brown location = new Location("fake"); 4462416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setLongitude(lngOffset); 4472416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setLatitude(0); 4482416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setAccuracy(417000.0f); 4492416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setTime(System.currentTimeMillis()); 4504118012da9a22694b3353040a485f8cdc27e2f17Philip Milne location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 4512416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4522416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 4532416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Estimated location from timezone: " + location); 4542416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4552416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4562416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4572416e09649eb6ab767eba458796e126196c77a34Jeff Brown setLocation(location); 4582416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4592416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4602416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void setLocation(Location location) { 4612416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation = location; 4622416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateTwilightState(); 4632416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4642416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4652416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void updateTwilightState() { 466b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown if (mLocation == null) { 467b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown setTwilightState(null); 468b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown return; 469b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown } 470b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown 4712416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long now = System.currentTimeMillis(); 4722416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4732416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate yesterday's twilight 4742416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS, 4752416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 4762416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long yesterdaySunset = mTwilightCalculator.mSunset; 4772416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4782416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate today's twilight 4792416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now, 4802416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 4812416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean isNight = (mTwilightCalculator.mState == TwilightCalculator.NIGHT); 4822416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long todaySunrise = mTwilightCalculator.mSunrise; 4832416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long todaySunset = mTwilightCalculator.mSunset; 4842416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4852416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate tomorrow's twilight 4862416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS, 4872416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 4882416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long tomorrowSunrise = mTwilightCalculator.mSunrise; 4892416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4902416e09649eb6ab767eba458796e126196c77a34Jeff Brown // set twilight state 4912416e09649eb6ab767eba458796e126196c77a34Jeff Brown TwilightState state = new TwilightState(isNight, yesterdaySunset, 4922416e09649eb6ab767eba458796e126196c77a34Jeff Brown todaySunrise, todaySunset, tomorrowSunrise); 4932416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 4942416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Updating twilight state: " + state); 4952416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4962416e09649eb6ab767eba458796e126196c77a34Jeff Brown setTwilightState(state); 4972416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4982416e09649eb6ab767eba458796e126196c77a34Jeff Brown // schedule next update 4992416e09649eb6ab767eba458796e126196c77a34Jeff Brown long nextUpdate = 0; 5002416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (todaySunrise == -1 || todaySunset == -1) { 5012416e09649eb6ab767eba458796e126196c77a34Jeff Brown // In the case the day or night never ends the update is scheduled 12 hours later. 5022416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS; 5032416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else { 5042416e09649eb6ab767eba458796e126196c77a34Jeff Brown // add some extra time to be on the safe side. 5052416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += DateUtils.MINUTE_IN_MILLIS; 5062416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5072416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (now > todaySunset) { 5082416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += tomorrowSunrise; 5092416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else if (now > todaySunrise) { 5102416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += todaySunset; 5112416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else { 5122416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += todaySunrise; 5132416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5142416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5152416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5162416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 5172416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Next update in " + (nextUpdate - now) + " ms"); 5182416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5192416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5202416e09649eb6ab767eba458796e126196c77a34Jeff Brown Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE); 5212416e09649eb6ab767eba458796e126196c77a34Jeff Brown PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, updateIntent, 0); 5222416e09649eb6ab767eba458796e126196c77a34Jeff Brown mAlarmManager.cancel(pendingIntent); 5232416e09649eb6ab767eba458796e126196c77a34Jeff Brown mAlarmManager.set(AlarmManager.RTC_WAKEUP, nextUpdate, pendingIntent); 5242416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5252416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 5262416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5272416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() { 5282416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 5292416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onReceive(Context context, Intent intent) { 5302416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction()) 5312416e09649eb6ab767eba458796e126196c77a34Jeff Brown && !intent.getBooleanExtra("state", false)) { 5322416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Airplane mode is now off! 5332416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.requestLocationUpdate(); 5342416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 5352416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5362416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5372416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Time zone has changed or alarm expired. 5382416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.requestTwilightUpdate(); 5392416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5402416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 5412416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5422416e09649eb6ab767eba458796e126196c77a34Jeff Brown // A LocationListener to initialize the network location provider. The location updates 5432416e09649eb6ab767eba458796e126196c77a34Jeff Brown // are handled through the passive location provider. 5442416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationListener mEmptyLocationListener = new LocationListener() { 5452416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onLocationChanged(Location location) { 5462416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5472416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5482416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderDisabled(String provider) { 5492416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5502416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5512416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderEnabled(String provider) { 5522416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5532416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5542416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onStatusChanged(String provider, int status, Bundle extras) { 5552416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5562416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 5572416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5582416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationListener mLocationListener = new LocationListener() { 5592416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onLocationChanged(Location location) { 5602416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.processNewLocation(location); 5612416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5622416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5632416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderDisabled(String provider) { 5642416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5652416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5662416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderEnabled(String provider) { 5672416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5682416e09649eb6ab767eba458796e126196c77a34Jeff Brown 5692416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onStatusChanged(String provider, int status, Bundle extras) { 5702416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 5712416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 5722416e09649eb6ab767eba458796e126196c77a34Jeff Brown} 573