1e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly/* 24cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * Copyright (C) 2012 The Android Open Source Project 3e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * 4e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * Licensed under the Apache License, Version 2.0 (the "License"); 5e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * you may not use this file except in compliance with the License. 6e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * You may obtain a copy of the License at 7e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * 8e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * http://www.apache.org/licenses/LICENSE-2.0 9e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * 10e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * Unless required by applicable law or agreed to in writing, software 11e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * distributed under the License is distributed on an "AS IS" BASIS, 12e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * See the License for the specific language governing permissions and 14e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * limitations under the License. 15e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly */ 16e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 17e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellypackage com.android.server.location; 18e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 19e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport java.io.PrintWriter; 20e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport java.util.Iterator; 21e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport java.util.LinkedList; 22e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport java.util.List; 23e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 245e45ee6752528791deb66b83d76250685de15d47Dianne Hackbornimport android.app.AppOpsManager; 25e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.app.PendingIntent; 26e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.content.Context; 27e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.content.Intent; 286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.location.Geofence; 29e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.location.Location; 30e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.location.LocationListener; 31e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.location.LocationManager; 326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pellyimport android.location.LocationRequest; 33e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.os.Bundle; 344cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Leaseimport android.os.Handler; 354cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Leaseimport android.os.Message; 36e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.os.PowerManager; 37e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellyimport android.os.SystemClock; 384cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Leaseimport android.util.Slog; 394035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly 404035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pellyimport com.android.server.LocationManagerService; 41e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 42e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pellypublic class GeofenceManager implements LocationListener, PendingIntent.OnFinished { 436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private static final String TAG = "GeofenceManager"; 444035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly private static final boolean D = LocationManagerService.D; 45e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 464cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private static final int MSG_UPDATE_FENCES = 1; 474cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 48e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly /** 49e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * Assume a maximum land speed, as a heuristic to throttle location updates. 50e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * (Air travel should result in an airplane mode toggle which will 51e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly * force a new location update anyway). 52e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly */ 536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private static final int MAX_SPEED_M_S = 100; // 360 km/hr (high speed train) 54e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 554cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 564cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * Maximum age after which a location is no longer considered fresh enough to use. 574cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 584cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private static final long MAX_AGE_NANOS = 5 * 60 * 1000000000L; // five minutes 594cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 604cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 614cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * Most frequent update interval allowed. 624cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 634cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private static final long MIN_INTERVAL_MS = 1 * 60 * 1000; // one minute 644cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 654cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 664cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * Least frequent update interval allowed. 674cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 684cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private static final long MAX_INTERVAL_MS = 2 * 60 * 60 * 1000; // two hours 694cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 706fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private final Context mContext; 716fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private final LocationManager mLocationManager; 725e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn private final AppOpsManager mAppOps; 736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private final PowerManager.WakeLock mWakeLock; 744cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private final GeofenceHandler mHandler; 754035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly private final LocationBlacklist mBlacklist; 76e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private Object mLock = new Object(); 786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly 796fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly // access to members below is synchronized on mLock 804cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 814cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * A list containing all registered geofences. 824cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 836fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private List<GeofenceState> mFences = new LinkedList<GeofenceState>(); 84e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 854cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 864cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * This is set true when we have an active request for {@link Location} updates via 874cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * {@link LocationManager#requestLocationUpdates(LocationRequest, LocationListener, 884cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * android.os.Looper). 894cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 904cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private boolean mReceivingLocationUpdates; 914cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 924cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 934cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * The update interval component of the current active {@link Location} update request. 944cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 954cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private long mLocationUpdateInterval; 964cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 974cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 984cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * The {@link Location} most recently received via {@link #onLocationChanged(Location)}. 994cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 1004cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private Location mLastLocationUpdate; 1014cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 1024cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 1034cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * This is set true when a {@link Location} is received via 1044cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * {@link #onLocationChanged(Location)} or {@link #scheduleUpdateFencesLocked()}, and cleared 1054cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * when that Location has been processed via {@link #updateFences()} 1064cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 1074cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private boolean mPendingUpdate; 1084cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 1094035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly public GeofenceManager(Context context, LocationBlacklist blacklist) { 110e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly mContext = context; 111e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly mLocationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); 1125e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE); 113e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); 114e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); 1154cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mHandler = new GeofenceHandler(); 1164035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly mBlacklist = blacklist; 1176fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } 1186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly 1194cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent, 1205e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn int allowedResolutionLevel, int uid, String packageName) { 1214cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 1224cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "addFence: request=" + request + ", geofence=" + geofence 1234cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + ", intent=" + intent + ", uid=" + uid + ", packageName=" + packageName); 1244cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 1256fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly 1264cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease GeofenceState state = new GeofenceState(geofence, 1275e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn request.getExpireAt(), allowedResolutionLevel, uid, packageName, intent); 1286fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly synchronized (mLock) { 1296fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly // first make sure it doesn't already exist 1306fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly for (int i = mFences.size() - 1; i >= 0; i--) { 1316fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly GeofenceState w = mFences.get(i); 1326fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (geofence.equals(w.mFence) && intent.equals(w.mIntent)) { 1336fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly // already exists, remove the old one 1346fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly mFences.remove(i); 1356fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly break; 1366fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } 1376fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } 1386fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly mFences.add(state); 1394cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease scheduleUpdateFencesLocked(); 140e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 141e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 142e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 1436fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly public void removeFence(Geofence fence, PendingIntent intent) { 1444cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 1454cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "removeFence: fence=" + fence + ", intent=" + intent); 1464cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 1474cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 1486fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly synchronized (mLock) { 1496fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly Iterator<GeofenceState> iter = mFences.iterator(); 150e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly while (iter.hasNext()) { 1516fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly GeofenceState state = iter.next(); 1526fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (state.mIntent.equals(intent)) { 1536fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly 1546fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (fence == null) { 1554cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // always remove 1566fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly iter.remove(); 1576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } else { 1586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly // just remove matching fences 1596fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (fence.equals(state.mFence)) { 1606fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly iter.remove(); 1616fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } 1626fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly } 163e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 164e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 1654cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease scheduleUpdateFencesLocked(); 166e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 167e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 168e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 169e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void removeFence(String packageName) { 1704cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 1714cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "removeFence: packageName=" + packageName); 1724cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 1734cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 1746fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly synchronized (mLock) { 1756fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly Iterator<GeofenceState> iter = mFences.iterator(); 176e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly while (iter.hasNext()) { 1776fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly GeofenceState state = iter.next(); 1786fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (state.mPackageName.equals(packageName)) { 179e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly iter.remove(); 180e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 181e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 1824cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease scheduleUpdateFencesLocked(); 183e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 184e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 185e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 1866fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private void removeExpiredFencesLocked() { 1876fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly long time = SystemClock.elapsedRealtime(); 1886fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly Iterator<GeofenceState> iter = mFences.iterator(); 1896fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly while (iter.hasNext()) { 1906fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly GeofenceState state = iter.next(); 1916fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly if (state.mExpireAt < time) { 1926fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly iter.remove(); 193e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 194e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 195e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 196e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 1974cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private void scheduleUpdateFencesLocked() { 1984cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (!mPendingUpdate) { 1994cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mPendingUpdate = true; 2004cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mHandler.sendEmptyMessage(MSG_UPDATE_FENCES); 2014cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2024cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2034cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2044cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 2054cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * Returns the location received most recently from {@link #onLocationChanged(Location)}, 2064cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * or consult {@link LocationManager#getLastLocation()} if none has arrived. Does not return 2074cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * either if the location would be too stale to be useful. 2084cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * 2094cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * @return a fresh, valid Location, or null if none is available 2104cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 2114cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private Location getFreshLocationLocked() { 2124cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Prefer mLastLocationUpdate to LocationManager.getLastLocation(). 2134cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Location location = mReceivingLocationUpdates ? mLastLocationUpdate : null; 2144cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (location == null && !mFences.isEmpty()) { 2154cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease location = mLocationManager.getLastLocation(); 2164cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2174cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2184cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Early out for null location. 2194cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (location == null) { 2204cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease return null; 2214cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2224cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2234cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Early out for stale location. 2244cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease long now = SystemClock.elapsedRealtimeNanos(); 2254cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (now - location.getElapsedRealtimeNanos() > MAX_AGE_NANOS) { 2264cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease return null; 2274cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2284cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2294cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Made it this far? Return our fresh, valid location. 2304cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease return location; 2314cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2324cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2334cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease /** 2344cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * The geofence update loop. This function removes expired fences, then tests the most 2354cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * recently-received {@link Location} against each registered {@link GeofenceState}, sending 2364cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * {@link Intent}s for geofences that have been tripped. It also adjusts the active location 2374cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease * update request with {@link LocationManager} as appropriate for any active geofences. 2384cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease */ 2394cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Runs on the handler. 2404cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private void updateFences() { 241e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly List<PendingIntent> enterIntents = new LinkedList<PendingIntent>(); 242e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly List<PendingIntent> exitIntents = new LinkedList<PendingIntent>(); 243e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 2446fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly synchronized (mLock) { 2454cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mPendingUpdate = false; 2464cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2474cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Remove expired fences. 2486fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly removeExpiredFencesLocked(); 249e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 2504cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Get a location to work with, either received via onLocationChanged() or 2514cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // via LocationManager.getLastLocation(). 2524cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Location location = getFreshLocationLocked(); 2534cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2544cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Update all fences. 2554cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Keep track of the distance to the nearest fence. 2564cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease double minFenceDistance = Double.MAX_VALUE; 2574cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease boolean needUpdates = false; 2586fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly for (GeofenceState state : mFences) { 2594035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly if (mBlacklist.isBlacklisted(state.mPackageName)) { 2604cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 2614cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "skipping geofence processing for blacklisted app: " 2624cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + state.mPackageName); 2634cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2644035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly continue; 2654035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly } 2664035f5a7c191a68bc9a5912ce44c43c82e9e5dbfNick Pelly 2675e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn int op = LocationManagerService.resolutionLevelToOp(state.mAllowedResolutionLevel); 2685e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn if (op >= 0) { 2695e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn if (mAppOps.noteOpNoThrow(AppOpsManager.OP_FINE_LOCATION, state.mUid, 2705e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn state.mPackageName) != AppOpsManager.MODE_ALLOWED) { 2715e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn if (D) { 2725e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn Slog.d(TAG, "skipping geofence processing for no op app: " 2735e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn + state.mPackageName); 2745e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn } 2755e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn continue; 2765e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn } 2775e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn } 2785e45ee6752528791deb66b83d76250685de15d47Dianne Hackborn 2794cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease needUpdates = true; 2804cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (location != null) { 2814cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease int event = state.processLocation(location); 2824cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if ((event & GeofenceState.FLAG_ENTER) != 0) { 2834cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease enterIntents.add(state.mIntent); 2844cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2854cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if ((event & GeofenceState.FLAG_EXIT) != 0) { 2864cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease exitIntents.add(state.mIntent); 2874cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2884cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2894cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // FIXME: Ideally this code should take into account the accuracy of the 2904cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // location fix that was used to calculate the distance in the first place. 2914cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease double fenceDistance = state.getDistanceToBoundary(); // MAX_VALUE if unknown 2924cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (fenceDistance < minFenceDistance) { 2934cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease minFenceDistance = fenceDistance; 2944cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2954cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2964cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 2974cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 2984cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Request or cancel location updates if needed. 2994cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (needUpdates) { 3004cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Request location updates. 3014cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Compute a location update interval based on the distance to the nearest fence. 3024cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease long intervalMs; 3034cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (location != null && Double.compare(minFenceDistance, Double.MAX_VALUE) != 0) { 3044cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease intervalMs = (long)Math.min(MAX_INTERVAL_MS, Math.max(MIN_INTERVAL_MS, 3054cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease minFenceDistance * 1000 / MAX_SPEED_M_S)); 3064cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } else { 3074cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease intervalMs = MIN_INTERVAL_MS; 308e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 3094cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (!mReceivingLocationUpdates || mLocationUpdateInterval != intervalMs) { 3104cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mReceivingLocationUpdates = true; 3114cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLocationUpdateInterval = intervalMs; 3124cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLastLocationUpdate = location; 3134cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 3144cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease LocationRequest request = new LocationRequest(); 3154cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease request.setInterval(intervalMs).setFastestInterval(0); 3164cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLocationManager.requestLocationUpdates(request, this, mHandler.getLooper()); 317e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 3184cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } else { 3194cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Cancel location updates. 3204cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (mReceivingLocationUpdates) { 3214cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mReceivingLocationUpdates = false; 3224cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLocationUpdateInterval = 0; 3234cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLastLocationUpdate = null; 3244cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 3254cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLocationManager.removeUpdates(this); 3264cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 3274cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 3284cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 3294cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 3304cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "updateFences: location=" + location 3314cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + ", mFences.size()=" + mFences.size() 3324cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + ", mReceivingLocationUpdates=" + mReceivingLocationUpdates 3334cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + ", mLocationUpdateInterval=" + mLocationUpdateInterval 3344cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease + ", mLastLocationUpdate=" + mLastLocationUpdate); 335e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 336e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 337e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 338e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly // release lock before sending intents 339e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly for (PendingIntent intent : exitIntents) { 340e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly sendIntentExit(intent); 341e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 342e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly for (PendingIntent intent : enterIntents) { 343e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly sendIntentEnter(intent); 344e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 345e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 346e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 3476fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private void sendIntentEnter(PendingIntent pendingIntent) { 3484cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 3494cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "sendIntentEnter: pendingIntent=" + pendingIntent); 3504cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 3514cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 352e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly Intent intent = new Intent(); 353e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true); 354e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly sendIntent(pendingIntent, intent); 355e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 356e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 3576fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private void sendIntentExit(PendingIntent pendingIntent) { 3584cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (D) { 3594cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease Slog.d(TAG, "sendIntentExit: pendingIntent=" + pendingIntent); 3604cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 3614cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 362e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly Intent intent = new Intent(); 363e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly intent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false); 364e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly sendIntent(pendingIntent, intent); 365e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 366e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 3676fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly private void sendIntent(PendingIntent pendingIntent, Intent intent) { 3684cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mWakeLock.acquire(); 369e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly try { 3704cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease pendingIntent.send(mContext, 0, intent, this, null, 3714cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease android.Manifest.permission.ACCESS_FINE_LOCATION); 372e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } catch (PendingIntent.CanceledException e) { 3736fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly removeFence(null, pendingIntent); 374e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly mWakeLock.release(); 375e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 3764cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // ...otherwise, mWakeLock.release() gets called by onSendFinished() 377e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 378e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 3794cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Runs on the handler (which was passed into LocationManager.requestLocationUpdates()) 3804cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease @Override 3814cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease public void onLocationChanged(Location location) { 3824cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease synchronized (mLock) { 3834cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (mReceivingLocationUpdates) { 3844cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mLastLocationUpdate = location; 385e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 386e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 3874cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // Update the fences immediately before returning in 3884cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease // case the caller is holding a wakelock. 3894cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease if (mPendingUpdate) { 3904cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mHandler.removeMessages(MSG_UPDATE_FENCES); 3914cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } else { 3924cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease mPendingUpdate = true; 3934cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 394e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 3954cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease updateFences(); 396e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 397e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 398e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly @Override 399e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void onStatusChanged(String provider, int status, Bundle extras) { } 400e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 401e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly @Override 402e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void onProviderEnabled(String provider) { } 403e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 404e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly @Override 405e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void onProviderDisabled(String provider) { } 406e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 407e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly @Override 408e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void onSendFinished(PendingIntent pendingIntent, Intent intent, int resultCode, 409e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly String resultData, Bundle resultExtras) { 410e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly mWakeLock.release(); 411e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 412e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly 413e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly public void dump(PrintWriter pw) { 414e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly pw.println(" Geofences:"); 4156fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly 4166fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly for (GeofenceState state : mFences) { 417e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly pw.append(" "); 4186fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly pw.append(state.mPackageName); 419e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly pw.append(" "); 4206fa9ad4afcd762aea519ff61811386c23d18ddb2Nick Pelly pw.append(state.mFence.toString()); 421e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly pw.append("\n"); 422e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 423e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly } 4244cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 4254cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease private final class GeofenceHandler extends Handler { 4264cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease public GeofenceHandler() { 4274cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease super(true /*async*/); 4284cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 4294cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease 4304cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease @Override 4314cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease public void handleMessage(Message msg) { 4324cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease switch (msg.what) { 4334cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease case MSG_UPDATE_FENCES: { 4344cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease updateFences(); 4354cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease break; 4364cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 4374cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 4384cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 4394cd0a50b26eeb68517d03bc0cafc18e98bfc1fecVictoria Lease } 440e0fd693c6098f59004f9e96ad75c058e26c337b0Nick Pelly} 441