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 17182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskipackage com.android.server.twilight; 18182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 19182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport com.android.server.SystemService; 20182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskiimport com.android.server.TwilightCalculator; 212416e09649eb6ab767eba458796e126196c77a34Jeff Brown 222416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.app.AlarmManager; 232416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.app.PendingIntent; 242416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.BroadcastReceiver; 252416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.Context; 262416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.Intent; 272416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.content.IntentFilter; 282416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.Criteria; 292416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.Location; 302416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.LocationListener; 312416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.location.LocationManager; 322416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Bundle; 332416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Handler; 342416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.Message; 352416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.os.SystemClock; 362416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.text.format.DateUtils; 372416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.text.format.Time; 382416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport android.util.Slog; 392416e09649eb6ab767eba458796e126196c77a34Jeff Brown 402416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.util.ArrayList; 412416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport java.util.Iterator; 422416e09649eb6ab767eba458796e126196c77a34Jeff Brown 432416e09649eb6ab767eba458796e126196c77a34Jeff Brownimport libcore.util.Objects; 442416e09649eb6ab767eba458796e126196c77a34Jeff Brown 452416e09649eb6ab767eba458796e126196c77a34Jeff Brown/** 462416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Figures out whether it's twilight time based on the user's location. 472416e09649eb6ab767eba458796e126196c77a34Jeff Brown * 482416e09649eb6ab767eba458796e126196c77a34Jeff Brown * Used by the UI mode manager and other components to adjust night mode 492416e09649eb6ab767eba458796e126196c77a34Jeff Brown * effects based on sunrise and sunset. 502416e09649eb6ab767eba458796e126196c77a34Jeff Brown */ 51182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinskipublic final class TwilightService extends SystemService { 52182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski static final String TAG = "TwilightService"; 53182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski static final boolean DEBUG = false; 54182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski static final String ACTION_UPDATE_TWILIGHT_STATE = 552416e09649eb6ab767eba458796e126196c77a34Jeff Brown "com.android.server.action.UPDATE_TWILIGHT_STATE"; 562416e09649eb6ab767eba458796e126196c77a34Jeff Brown 57182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final Object mLock = new Object(); 582416e09649eb6ab767eba458796e126196c77a34Jeff Brown 59182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski AlarmManager mAlarmManager; 60182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski LocationManager mLocationManager; 61182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski LocationHandler mLocationHandler; 622416e09649eb6ab767eba458796e126196c77a34Jeff Brown 63182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final ArrayList<TwilightListenerRecord> mListeners = 642416e09649eb6ab767eba458796e126196c77a34Jeff Brown new ArrayList<TwilightListenerRecord>(); 652416e09649eb6ab767eba458796e126196c77a34Jeff Brown 66182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski TwilightState mTwilightState; 672416e09649eb6ab767eba458796e126196c77a34Jeff Brown 68b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown public TwilightService(Context context) { 69b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown super(context); 70b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown } 71b880d880c6cd989eacc28c365fc9a41d31900da1Jeff Brown 72182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 73182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void onStart() { 74182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE); 75182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mLocationManager = (LocationManager) getContext().getSystemService( 76182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski Context.LOCATION_SERVICE); 77182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mLocationHandler = new LocationHandler(); 782416e09649eb6ab767eba458796e126196c77a34Jeff Brown 79182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski IntentFilter filter = new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED); 80182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski filter.addAction(Intent.ACTION_TIME_CHANGED); 81182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); 82182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski filter.addAction(ACTION_UPDATE_TWILIGHT_STATE); 83182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski getContext().registerReceiver(mUpdateLocationReceiver, filter); 842416e09649eb6ab767eba458796e126196c77a34Jeff Brown 85182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski publishLocalService(TwilightManager.class, mService); 862416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 872416e09649eb6ab767eba458796e126196c77a34Jeff Brown 88182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private static class TwilightListenerRecord implements Runnable { 89182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final TwilightListener mListener; 90182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final Handler mHandler; 912416e09649eb6ab767eba458796e126196c77a34Jeff Brown 92182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public TwilightListenerRecord(TwilightListener listener, Handler handler) { 93182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mListener = listener; 94182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mHandler = handler; 95182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 962416e09649eb6ab767eba458796e126196c77a34Jeff Brown 97182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void postUpdate() { 98182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mHandler.post(this); 992416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1002416e09649eb6ab767eba458796e126196c77a34Jeff Brown 101182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 102182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void run() { 103182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mListener.onTwilightStateChanged(); 1042416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 105182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 1062416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1072416e09649eb6ab767eba458796e126196c77a34Jeff Brown 108182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski private final TwilightManager mService = new TwilightManager() { 109182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski /** 110182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * Gets the current twilight state. 111182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * 112182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * @return The current twilight state, or null if no information is available. 113182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski */ 114182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 115182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public TwilightState getCurrentState() { 116182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 117182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski return mTwilightState; 118182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 119182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 1202416e09649eb6ab767eba458796e126196c77a34Jeff Brown 121182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski /** 122182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * Listens for twilight time. 123182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * 124182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski * @param listener The listener. 125182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski */ 126182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski @Override 127182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski public void registerListener(TwilightListener listener, Handler handler) { 128182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski synchronized (mLock) { 129182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mListeners.add(new TwilightListenerRecord(listener, handler)); 130182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 131182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski if (mListeners.size() == 1) { 132182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mLocationHandler.enableLocationUpdates(); 133182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 1342416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1352416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 136182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski }; 1372416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1382416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void setTwilightState(TwilightState state) { 1392416e09649eb6ab767eba458796e126196c77a34Jeff Brown synchronized (mLock) { 1402416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!Objects.equal(mTwilightState, state)) { 1412416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 1422416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Twilight state changed: " + state); 1432416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1442416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1452416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightState = state; 146182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski 147182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski final int listenerLen = mListeners.size(); 148182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski for (int i = 0; i < listenerLen; i++) { 149182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski mListeners.get(i).postUpdate(); 1502416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1512416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1522416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1532416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1542416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1552416e09649eb6ab767eba458796e126196c77a34Jeff Brown // The user has moved if the accuracy circles of the two locations don't overlap. 1562416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static boolean hasMoved(Location from, Location to) { 1572416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (to == null) { 1582416e09649eb6ab767eba458796e126196c77a34Jeff Brown return false; 1592416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1602416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1612416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (from == null) { 1622416e09649eb6ab767eba458796e126196c77a34Jeff Brown return true; 1632416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1642416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1652416e09649eb6ab767eba458796e126196c77a34Jeff Brown // if new location is older than the current one, the device hasn't moved. 1664118012da9a22694b3353040a485f8cdc27e2f17Philip Milne if (to.getElapsedRealtimeNanos() < from.getElapsedRealtimeNanos()) { 1672416e09649eb6ab767eba458796e126196c77a34Jeff Brown return false; 1682416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1692416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1702416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Get the distance between the two points. 1712416e09649eb6ab767eba458796e126196c77a34Jeff Brown float distance = from.distanceTo(to); 1722416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1732416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Get the total accuracy radius for both locations. 1742416e09649eb6ab767eba458796e126196c77a34Jeff Brown float totalAccuracy = from.getAccuracy() + to.getAccuracy(); 1752416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1762416e09649eb6ab767eba458796e126196c77a34Jeff Brown // If the distance is greater than the combined accuracy of the two 1772416e09649eb6ab767eba458796e126196c77a34Jeff Brown // points then they can't overlap and hence the user has moved. 1782416e09649eb6ab767eba458796e126196c77a34Jeff Brown return distance >= totalAccuracy; 1792416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 1802416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1812416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final class LocationHandler extends Handler { 1822416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_ENABLE_LOCATION_UPDATES = 1; 1832416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_GET_NEW_LOCATION_UPDATE = 2; 1842416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_PROCESS_NEW_LOCATION = 3; 1852416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final int MSG_DO_TWILIGHT_UPDATE = 4; 1862416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1872416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_MS = 24 * DateUtils.HOUR_IN_MILLIS; 1882416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long MIN_LOCATION_UPDATE_MS = 30 * DateUtils.MINUTE_IN_MILLIS; 1892416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final float LOCATION_UPDATE_DISTANCE_METER = 1000 * 20; 1902416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MIN = 5000; 1912416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final long LOCATION_UPDATE_ENABLE_INTERVAL_MAX = 1922416e09649eb6ab767eba458796e126196c77a34Jeff Brown 15 * DateUtils.MINUTE_IN_MILLIS; 1932416e09649eb6ab767eba458796e126196c77a34Jeff Brown private static final double FACTOR_GMT_OFFSET_LONGITUDE = 1942416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1000.0 * 360.0 / DateUtils.DAY_IN_MILLIS; 1952416e09649eb6ab767eba458796e126196c77a34Jeff Brown 1962416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mPassiveListenerEnabled; 1972416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mNetworkListenerEnabled; 1982416e09649eb6ab767eba458796e126196c77a34Jeff Brown private boolean mDidFirstInit; 1992416e09649eb6ab767eba458796e126196c77a34Jeff Brown private long mLastNetworkRegisterTime = -MIN_LOCATION_UPDATE_MS; 2002416e09649eb6ab767eba458796e126196c77a34Jeff Brown private long mLastUpdateInterval; 2012416e09649eb6ab767eba458796e126196c77a34Jeff Brown private Location mLocation; 2022416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final TwilightCalculator mTwilightCalculator = new TwilightCalculator(); 2032416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2042416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void processNewLocation(Location location) { 2052416e09649eb6ab767eba458796e126196c77a34Jeff Brown Message msg = obtainMessage(MSG_PROCESS_NEW_LOCATION, location); 2062416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendMessage(msg); 2072416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2082416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2092416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void enableLocationUpdates() { 2102416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_ENABLE_LOCATION_UPDATES); 2112416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2122416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2132416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void requestLocationUpdate() { 2142416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_GET_NEW_LOCATION_UPDATE); 2152416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2162416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2172416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void requestTwilightUpdate() { 2182416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessage(MSG_DO_TWILIGHT_UPDATE); 2192416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2202416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2212416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 2222416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void handleMessage(Message msg) { 2232416e09649eb6ab767eba458796e126196c77a34Jeff Brown switch (msg.what) { 2242416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_PROCESS_NEW_LOCATION: { 2252416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Location location = (Location)msg.obj; 2262416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean hasMoved = hasMoved(mLocation, location); 2272416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean hasBetterAccuracy = mLocation == null 2282416e09649eb6ab767eba458796e126196c77a34Jeff Brown || location.getAccuracy() < mLocation.getAccuracy(); 2292416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 2302416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Processing new location: " + location 2312416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", hasMoved=" + hasMoved 2322416e09649eb6ab767eba458796e126196c77a34Jeff Brown + ", hasBetterAccuracy=" + hasBetterAccuracy); 2332416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2342416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (hasMoved || hasBetterAccuracy) { 2352416e09649eb6ab767eba458796e126196c77a34Jeff Brown setLocation(location); 2362416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2372416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 2382416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2392416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2402416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_GET_NEW_LOCATION_UPDATE: 2412416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mNetworkListenerEnabled) { 2422416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Don't do anything -- we are still trying to get a 2432416e09649eb6ab767eba458796e126196c77a34Jeff Brown // location. 2442416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 2452416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2462416e09649eb6ab767eba458796e126196c77a34Jeff Brown if ((mLastNetworkRegisterTime + MIN_LOCATION_UPDATE_MS) >= 2472416e09649eb6ab767eba458796e126196c77a34Jeff Brown SystemClock.elapsedRealtime()) { 2482416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Don't do anything -- it hasn't been long enough 2492416e09649eb6ab767eba458796e126196c77a34Jeff Brown // since we last requested an update. 2502416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 2512416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2522416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2532416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Unregister the current location monitor, so we can 2542416e09649eb6ab767eba458796e126196c77a34Jeff Brown // register a new one for it to get an immediate update. 2552416e09649eb6ab767eba458796e126196c77a34Jeff Brown mNetworkListenerEnabled = false; 2562416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.removeUpdates(mEmptyLocationListener); 2572416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2582416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Fall through to re-register listener. 2592416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_ENABLE_LOCATION_UPDATES: 2602416e09649eb6ab767eba458796e126196c77a34Jeff Brown // enable network provider to receive at least location updates for a given 2612416e09649eb6ab767eba458796e126196c77a34Jeff Brown // distance. 2622416e09649eb6ab767eba458796e126196c77a34Jeff Brown boolean networkLocationEnabled; 2632416e09649eb6ab767eba458796e126196c77a34Jeff Brown try { 2642416e09649eb6ab767eba458796e126196c77a34Jeff Brown networkLocationEnabled = 2652416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); 2662416e09649eb6ab767eba458796e126196c77a34Jeff Brown } catch (Exception e) { 2672416e09649eb6ab767eba458796e126196c77a34Jeff Brown // we may get IllegalArgumentException if network location provider 2682416e09649eb6ab767eba458796e126196c77a34Jeff Brown // does not exist or is not yet installed. 2692416e09649eb6ab767eba458796e126196c77a34Jeff Brown networkLocationEnabled = false; 2702416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2712416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mNetworkListenerEnabled && networkLocationEnabled) { 2722416e09649eb6ab767eba458796e126196c77a34Jeff Brown mNetworkListenerEnabled = true; 2732416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastNetworkRegisterTime = SystemClock.elapsedRealtime(); 2742416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 2752416e09649eb6ab767eba458796e126196c77a34Jeff Brown LOCATION_UPDATE_MS, 0, mEmptyLocationListener); 2762416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2772416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mDidFirstInit) { 2782416e09649eb6ab767eba458796e126196c77a34Jeff Brown mDidFirstInit = true; 2792416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (mLocation == null) { 2802416e09649eb6ab767eba458796e126196c77a34Jeff Brown retrieveLocation(); 2812416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2822416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2832416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2842416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2852416e09649eb6ab767eba458796e126196c77a34Jeff Brown // enable passive provider to receive updates from location fixes (gps 2862416e09649eb6ab767eba458796e126196c77a34Jeff Brown // and network). 2872416e09649eb6ab767eba458796e126196c77a34Jeff Brown boolean passiveLocationEnabled; 2882416e09649eb6ab767eba458796e126196c77a34Jeff Brown try { 2892416e09649eb6ab767eba458796e126196c77a34Jeff Brown passiveLocationEnabled = 2902416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.isProviderEnabled(LocationManager.PASSIVE_PROVIDER); 2912416e09649eb6ab767eba458796e126196c77a34Jeff Brown } catch (Exception e) { 2922416e09649eb6ab767eba458796e126196c77a34Jeff Brown // we may get IllegalArgumentException if passive location provider 2932416e09649eb6ab767eba458796e126196c77a34Jeff Brown // does not exist or is not yet installed. 2942416e09649eb6ab767eba458796e126196c77a34Jeff Brown passiveLocationEnabled = false; 2952416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 2962416e09649eb6ab767eba458796e126196c77a34Jeff Brown 2972416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!mPassiveListenerEnabled && passiveLocationEnabled) { 2982416e09649eb6ab767eba458796e126196c77a34Jeff Brown mPassiveListenerEnabled = true; 2992416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER, 3002416e09649eb6ab767eba458796e126196c77a34Jeff Brown 0, LOCATION_UPDATE_DISTANCE_METER , mLocationListener); 3012416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3022416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3032416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (!(mNetworkListenerEnabled && mPassiveListenerEnabled)) { 3042416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval *= 1.5; 3052416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (mLastUpdateInterval == 0) { 3062416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MIN; 3072416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else if (mLastUpdateInterval > LOCATION_UPDATE_ENABLE_INTERVAL_MAX) { 3082416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLastUpdateInterval = LOCATION_UPDATE_ENABLE_INTERVAL_MAX; 3092416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3102416e09649eb6ab767eba458796e126196c77a34Jeff Brown sendEmptyMessageDelayed(MSG_ENABLE_LOCATION_UPDATES, mLastUpdateInterval); 3112416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3122416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 3132416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3142416e09649eb6ab767eba458796e126196c77a34Jeff Brown case MSG_DO_TWILIGHT_UPDATE: 3152416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateTwilightState(); 3162416e09649eb6ab767eba458796e126196c77a34Jeff Brown break; 3172416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3182416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3192416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3202416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void retrieveLocation() { 3212416e09649eb6ab767eba458796e126196c77a34Jeff Brown Location location = null; 3222416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Iterator<String> providers = 3232416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.getProviders(new Criteria(), true).iterator(); 3242416e09649eb6ab767eba458796e126196c77a34Jeff Brown while (providers.hasNext()) { 3252416e09649eb6ab767eba458796e126196c77a34Jeff Brown final Location lastKnownLocation = 3262416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationManager.getLastKnownLocation(providers.next()); 3272416e09649eb6ab767eba458796e126196c77a34Jeff Brown // pick the most recent location 3282416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (location == null || (lastKnownLocation != null && 3294118012da9a22694b3353040a485f8cdc27e2f17Philip Milne location.getElapsedRealtimeNanos() < 3304118012da9a22694b3353040a485f8cdc27e2f17Philip Milne lastKnownLocation.getElapsedRealtimeNanos())) { 3312416e09649eb6ab767eba458796e126196c77a34Jeff Brown location = lastKnownLocation; 3322416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3332416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3342416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3352416e09649eb6ab767eba458796e126196c77a34Jeff Brown // In the case there is no location available (e.g. GPS fix or network location 3362416e09649eb6ab767eba458796e126196c77a34Jeff Brown // is not available yet), the longitude of the location is estimated using the timezone, 3372416e09649eb6ab767eba458796e126196c77a34Jeff Brown // latitude and accuracy are set to get a good average. 3382416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (location == null) { 3392416e09649eb6ab767eba458796e126196c77a34Jeff Brown Time currentTime = new Time(); 3402416e09649eb6ab767eba458796e126196c77a34Jeff Brown currentTime.set(System.currentTimeMillis()); 3412416e09649eb6ab767eba458796e126196c77a34Jeff Brown double lngOffset = FACTOR_GMT_OFFSET_LONGITUDE * 3422416e09649eb6ab767eba458796e126196c77a34Jeff Brown (currentTime.gmtoff - (currentTime.isDst > 0 ? 3600 : 0)); 3432416e09649eb6ab767eba458796e126196c77a34Jeff Brown location = new Location("fake"); 3442416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setLongitude(lngOffset); 3452416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setLatitude(0); 3462416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setAccuracy(417000.0f); 3472416e09649eb6ab767eba458796e126196c77a34Jeff Brown location.setTime(System.currentTimeMillis()); 3484118012da9a22694b3353040a485f8cdc27e2f17Philip Milne location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); 3492416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3502416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 3512416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Estimated location from timezone: " + location); 3522416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3532416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3542416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3552416e09649eb6ab767eba458796e126196c77a34Jeff Brown setLocation(location); 3562416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3572416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3582416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void setLocation(Location location) { 3592416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation = location; 3602416e09649eb6ab767eba458796e126196c77a34Jeff Brown updateTwilightState(); 3612416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3622416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3632416e09649eb6ab767eba458796e126196c77a34Jeff Brown private void updateTwilightState() { 364b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown if (mLocation == null) { 365b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown setTwilightState(null); 366b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown return; 367b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown } 368b5b710a4851db6c7e247429b0551a523c4d33da6Jeff Brown 3692416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long now = System.currentTimeMillis(); 3702416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3712416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate yesterday's twilight 3722416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now - DateUtils.DAY_IN_MILLIS, 3732416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 3742416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long yesterdaySunset = mTwilightCalculator.mSunset; 3752416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3762416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate today's twilight 3772416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now, 3782416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 3792416e09649eb6ab767eba458796e126196c77a34Jeff Brown final boolean isNight = (mTwilightCalculator.mState == TwilightCalculator.NIGHT); 3802416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long todaySunrise = mTwilightCalculator.mSunrise; 3812416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long todaySunset = mTwilightCalculator.mSunset; 3822416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3832416e09649eb6ab767eba458796e126196c77a34Jeff Brown // calculate tomorrow's twilight 3842416e09649eb6ab767eba458796e126196c77a34Jeff Brown mTwilightCalculator.calculateTwilight(now + DateUtils.DAY_IN_MILLIS, 3852416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocation.getLatitude(), mLocation.getLongitude()); 3862416e09649eb6ab767eba458796e126196c77a34Jeff Brown final long tomorrowSunrise = mTwilightCalculator.mSunrise; 3872416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3882416e09649eb6ab767eba458796e126196c77a34Jeff Brown // set twilight state 3892416e09649eb6ab767eba458796e126196c77a34Jeff Brown TwilightState state = new TwilightState(isNight, yesterdaySunset, 3902416e09649eb6ab767eba458796e126196c77a34Jeff Brown todaySunrise, todaySunset, tomorrowSunrise); 3912416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 3922416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Updating twilight state: " + state); 3932416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 3942416e09649eb6ab767eba458796e126196c77a34Jeff Brown setTwilightState(state); 3952416e09649eb6ab767eba458796e126196c77a34Jeff Brown 3962416e09649eb6ab767eba458796e126196c77a34Jeff Brown // schedule next update 3972416e09649eb6ab767eba458796e126196c77a34Jeff Brown long nextUpdate = 0; 3982416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (todaySunrise == -1 || todaySunset == -1) { 3992416e09649eb6ab767eba458796e126196c77a34Jeff Brown // In the case the day or night never ends the update is scheduled 12 hours later. 4002416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate = now + 12 * DateUtils.HOUR_IN_MILLIS; 4012416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else { 4022416e09649eb6ab767eba458796e126196c77a34Jeff Brown // add some extra time to be on the safe side. 4032416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += DateUtils.MINUTE_IN_MILLIS; 4042416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4052416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (now > todaySunset) { 4062416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += tomorrowSunrise; 4072416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else if (now > todaySunrise) { 4082416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += todaySunset; 4092416e09649eb6ab767eba458796e126196c77a34Jeff Brown } else { 4102416e09649eb6ab767eba458796e126196c77a34Jeff Brown nextUpdate += todaySunrise; 4112416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4122416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4132416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4142416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (DEBUG) { 4152416e09649eb6ab767eba458796e126196c77a34Jeff Brown Slog.d(TAG, "Next update in " + (nextUpdate - now) + " ms"); 4162416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4172416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4182416e09649eb6ab767eba458796e126196c77a34Jeff Brown Intent updateIntent = new Intent(ACTION_UPDATE_TWILIGHT_STATE); 419182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski PendingIntent pendingIntent = PendingIntent.getBroadcast( 420182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski getContext(), 0, updateIntent, 0); 4212416e09649eb6ab767eba458796e126196c77a34Jeff Brown mAlarmManager.cancel(pendingIntent); 4227359766116e14f90d74776e1b85042009ab2cdd7Christopher Tate mAlarmManager.setExact(AlarmManager.RTC, nextUpdate, pendingIntent); 4232416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 424182f73fc4da13a6417e5086ec9ecce80eb8423caAdam Lesinski } 4252416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4262416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final BroadcastReceiver mUpdateLocationReceiver = new BroadcastReceiver() { 4272416e09649eb6ab767eba458796e126196c77a34Jeff Brown @Override 4282416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onReceive(Context context, Intent intent) { 4292416e09649eb6ab767eba458796e126196c77a34Jeff Brown if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(intent.getAction()) 4302416e09649eb6ab767eba458796e126196c77a34Jeff Brown && !intent.getBooleanExtra("state", false)) { 4312416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Airplane mode is now off! 4322416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.requestLocationUpdate(); 4332416e09649eb6ab767eba458796e126196c77a34Jeff Brown return; 4342416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4352416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4362416e09649eb6ab767eba458796e126196c77a34Jeff Brown // Time zone has changed or alarm expired. 4372416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.requestTwilightUpdate(); 4382416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4392416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 4402416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4412416e09649eb6ab767eba458796e126196c77a34Jeff Brown // A LocationListener to initialize the network location provider. The location updates 4422416e09649eb6ab767eba458796e126196c77a34Jeff Brown // are handled through the passive location provider. 4432416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationListener mEmptyLocationListener = new LocationListener() { 4442416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onLocationChanged(Location location) { 4452416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4462416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4472416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderDisabled(String provider) { 4482416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4492416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4502416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderEnabled(String provider) { 4512416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4522416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4532416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onStatusChanged(String provider, int status, Bundle extras) { 4542416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4552416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 4562416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4572416e09649eb6ab767eba458796e126196c77a34Jeff Brown private final LocationListener mLocationListener = new LocationListener() { 4582416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onLocationChanged(Location location) { 4592416e09649eb6ab767eba458796e126196c77a34Jeff Brown mLocationHandler.processNewLocation(location); 4602416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4612416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4622416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderDisabled(String provider) { 4632416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4642416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4652416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onProviderEnabled(String provider) { 4662416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4672416e09649eb6ab767eba458796e126196c77a34Jeff Brown 4682416e09649eb6ab767eba458796e126196c77a34Jeff Brown public void onStatusChanged(String provider, int status, Bundle extras) { 4692416e09649eb6ab767eba458796e126196c77a34Jeff Brown } 4702416e09649eb6ab767eba458796e126196c77a34Jeff Brown }; 4712416e09649eb6ab767eba458796e126196c77a34Jeff Brown} 472