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