blob: 1498a115534d465eb9cce07ca3d571b321e5911e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080019import android.app.Activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020import android.app.PendingIntent;
21import android.content.BroadcastReceiver;
Mike Lockwood9637d472009-04-02 21:41:57 -070022import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.pm.PackageManager;
Nick Pelly00355d52012-05-27 16:12:45 -070028import android.content.pm.ResolveInfo;
Mike Lockwood628fd6d2010-01-25 22:46:13 -050029import android.content.res.Resources;
Mike Lockwood9637d472009-04-02 21:41:57 -070030import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.location.Address;
Mike Lockwood03ca2162010-04-01 08:10:09 -070032import android.location.Criteria;
Mike Lockwood34901402010-01-04 12:14:21 -050033import android.location.GeocoderParams;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040035import android.location.IGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.location.ILocationListener;
37import android.location.ILocationManager;
Danke Xie22d1f9f2009-08-18 18:28:45 -040038import android.location.INetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.location.Location;
40import android.location.LocationManager;
41import android.location.LocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.net.ConnectivityManager;
Mike Lockwood03d24672009-10-08 15:45:03 -040043import android.net.NetworkInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.Binder;
45import android.os.Bundle;
46import android.os.Handler;
47import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070048import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Message;
50import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070051import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.os.RemoteException;
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -070053import android.os.WorkSource;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.provider.Settings;
Nick Pellye0fd6932012-07-11 10:26:13 -070055import android.provider.Settings.NameValueTable;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.util.Log;
Joe Onorato8a9b2202010-02-26 18:56:32 -080057import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.util.PrintWriterPrinter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
Mike Lockwoode97ae402010-09-29 15:23:46 -040060import com.android.internal.content.PackageMonitor;
Mike Lockwood43e33f22010-03-26 10:41:48 -040061
62import com.android.server.location.GeocoderProxy;
Nick Pellye0fd6932012-07-11 10:26:13 -070063import com.android.server.location.GeofenceManager;
Mike Lockwood43e33f22010-03-26 10:41:48 -040064import com.android.server.location.GpsLocationProvider;
65import com.android.server.location.LocationProviderInterface;
66import com.android.server.location.LocationProviderProxy;
67import com.android.server.location.MockProvider;
68import com.android.server.location.PassiveProvider;
69
70import java.io.FileDescriptor;
71import java.io.PrintWriter;
72import java.util.ArrayList;
Mike Lockwood03ca2162010-04-01 08:10:09 -070073import java.util.Collections;
74import java.util.Comparator;
Mike Lockwood43e33f22010-03-26 10:41:48 -040075import java.util.HashMap;
76import java.util.HashSet;
77import java.util.List;
78import java.util.Map;
79import java.util.Observable;
80import java.util.Observer;
81import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082
83/**
84 * The service class that manages LocationProviders and issues location
85 * updates and alerts.
86 *
87 * {@hide}
88 */
Mike Lockwood3d12b512009-04-21 23:25:35 -070089public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090 private static final String TAG = "LocationManagerService";
Mike Lockwood4a7b65e2010-10-25 16:35:55 -040091 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 private static final String ACCESS_FINE_LOCATION =
94 android.Manifest.permission.ACCESS_FINE_LOCATION;
95 private static final String ACCESS_COARSE_LOCATION =
96 android.Manifest.permission.ACCESS_COARSE_LOCATION;
97 private static final String ACCESS_MOCK_LOCATION =
98 android.Manifest.permission.ACCESS_MOCK_LOCATION;
99 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
100 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
Mike Lockwood275555c2009-05-01 11:30:34 -0400101 private static final String INSTALL_LOCATION_PROVIDER =
102 android.Manifest.permission.INSTALL_LOCATION_PROVIDER;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
Nick Pellyf1be6862012-05-15 10:53:42 -0700104 // Location Providers may sometimes deliver location updates
105 // slightly faster that requested - provide grace period so
106 // we don't unnecessarily filter events that are otherwise on
107 // time
108 private static final int MAX_PROVIDER_SCHEDULING_JITTER = 100;
109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110 // Set of providers that are explicitly enabled
111 private final Set<String> mEnabledProviders = new HashSet<String>();
112
113 // Set of providers that are explicitly disabled
114 private final Set<String> mDisabledProviders = new HashSet<String>();
115
116 // Locations, status values, and extras for mock providers
Mike Lockwood7ec434e2009-03-27 07:46:48 -0700117 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118
119 private static boolean sProvidersLoaded = false;
120
121 private final Context mContext;
Nick Pelly00355d52012-05-27 16:12:45 -0700122 private PackageManager mPackageManager; // final after initialize()
123 private String mNetworkLocationProviderPackageName; // only used on handler thread
124 private String mGeocodeProviderPackageName; // only used on handler thread
Mike Lockwood628fd6d2010-01-25 22:46:13 -0500125 private GeocoderProxy mGeocodeProvider;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400126 private IGpsStatusProvider mGpsStatusProvider;
Danke Xie22d1f9f2009-08-18 18:28:45 -0400127 private INetInitiatedListener mNetInitiatedListener;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 private LocationWorkerHandler mLocationHandler;
129
Mike Lockwood7566c1d2009-08-25 10:05:18 -0700130 // Cache the real providers for use in addTestProvider() and removeTestProvider()
Mike Lockwoode97ae402010-09-29 15:23:46 -0400131 LocationProviderProxy mNetworkLocationProvider;
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500132 LocationProviderInterface mGpsLocationProvider;
Mike Lockwood7566c1d2009-08-25 10:05:18 -0700133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 // Handler messages
Mike Lockwood4e50b782009-04-03 08:24:43 -0700135 private static final int MESSAGE_LOCATION_CHANGED = 1;
Mark Vandevoorde8863c432010-10-04 14:23:24 -0700136 private static final int MESSAGE_PACKAGE_UPDATED = 2;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800137
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400138 // wakelock variables
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 private final static String WAKELOCK_KEY = "LocationManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private PowerManager.WakeLock mWakeLock = null;
Mike Lockwood48f17512009-04-23 09:12:08 -0700141 private int mPendingBroadcasts;
Nick Pellye0fd6932012-07-11 10:26:13 -0700142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400144 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400146 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400148
149 /**
150 * List of location providers.
151 */
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500152 private final ArrayList<LocationProviderInterface> mProviders =
153 new ArrayList<LocationProviderInterface>();
154 private final HashMap<String, LocationProviderInterface> mProvidersByName
155 = new HashMap<String, LocationProviderInterface>();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400158 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400160 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161
162 /**
163 * Mapping from provider name to all its UpdateRecords
164 */
165 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
166 new HashMap<String,ArrayList<UpdateRecord>>();
167
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -0700168 /**
169 * Temporary filled in when computing min time for a provider. Access is
170 * protected by global lock mLock.
171 */
172 private final WorkSource mTmpWorkSource = new WorkSource();
173
Nick Pellye0fd6932012-07-11 10:26:13 -0700174 GeofenceManager mGeofenceManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175
176 // Last known location for each provider
177 private HashMap<String,Location> mLastKnownLocation =
178 new HashMap<String,Location>();
179
The Android Open Source Project4df24232009-03-05 14:34:35 -0800180 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800181
Mike Lockwood9637d472009-04-02 21:41:57 -0700182 // for Settings change notification
183 private ContentQueryMap mSettings;
184
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800185 /**
186 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
187 * location updates.
188 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700189 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 final ILocationListener mListener;
191 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 final Object mKey;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400193 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Nick Pellyf1be6862012-05-15 10:53:42 -0700194
Mike Lockwood48f17512009-04-23 09:12:08 -0700195 int mPendingBroadcasts;
Nick Pellyf1be6862012-05-15 10:53:42 -0700196 String mRequiredPermissions;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400198 Receiver(ILocationListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800199 mListener = listener;
200 mPendingIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800201 mKey = listener.asBinder();
202 }
203
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400204 Receiver(PendingIntent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800205 mPendingIntent = intent;
206 mListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 mKey = intent;
208 }
209
210 @Override
211 public boolean equals(Object otherObj) {
212 if (otherObj instanceof Receiver) {
213 return mKey.equals(
214 ((Receiver)otherObj).mKey);
215 }
216 return false;
217 }
218
219 @Override
220 public int hashCode() {
221 return mKey.hashCode();
222 }
Mike Lockwood3681f262009-05-12 10:52:03 -0400223
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800224 @Override
225 public String toString() {
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400226 String result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 if (mListener != null) {
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400228 result = "Receiver{"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800229 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400230 + " Listener " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 } else {
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400232 result = "Receiver{"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400234 + " Intent " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 }
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -0400236 result += "mUpdateRecords: " + mUpdateRecords;
237 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 }
239
240 public boolean isListener() {
241 return mListener != null;
242 }
243
244 public boolean isPendingIntent() {
245 return mPendingIntent != null;
246 }
247
248 public ILocationListener getListener() {
249 if (mListener != null) {
250 return mListener;
251 }
252 throw new IllegalStateException("Request for non-existent listener");
253 }
254
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
256 if (mListener != null) {
257 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700258 synchronized (this) {
259 // synchronize to ensure incrementPendingBroadcastsLocked()
260 // is called before decrementPendingBroadcasts()
261 mListener.onStatusChanged(provider, status, extras);
Nick Pellye0fd6932012-07-11 10:26:13 -0700262 // call this after broadcasting so we do not increment
263 // if we throw an exeption.
264 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700265 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 } catch (RemoteException e) {
267 return false;
268 }
269 } else {
270 Intent statusChanged = new Intent();
271 statusChanged.putExtras(extras);
272 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
273 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700274 synchronized (this) {
275 // synchronize to ensure incrementPendingBroadcastsLocked()
276 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700277 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
Nick Pellyf1be6862012-05-15 10:53:42 -0700278 mRequiredPermissions);
Mike Lockwood48f17512009-04-23 09:12:08 -0700279 // call this after broadcasting so we do not increment
280 // if we throw an exeption.
281 incrementPendingBroadcastsLocked();
282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283 } catch (PendingIntent.CanceledException e) {
284 return false;
285 }
286 }
287 return true;
288 }
289
290 public boolean callLocationChangedLocked(Location location) {
291 if (mListener != null) {
292 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700293 synchronized (this) {
294 // synchronize to ensure incrementPendingBroadcastsLocked()
295 // is called before decrementPendingBroadcasts()
296 mListener.onLocationChanged(location);
Nick Pellye0fd6932012-07-11 10:26:13 -0700297 // call this after broadcasting so we do not increment
298 // if we throw an exeption.
299 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 } catch (RemoteException e) {
302 return false;
303 }
304 } else {
305 Intent locationChanged = new Intent();
306 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
307 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700308 synchronized (this) {
309 // synchronize to ensure incrementPendingBroadcastsLocked()
310 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700311 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
Nick Pellyf1be6862012-05-15 10:53:42 -0700312 mRequiredPermissions);
Mike Lockwood48f17512009-04-23 09:12:08 -0700313 // call this after broadcasting so we do not increment
314 // if we throw an exeption.
315 incrementPendingBroadcastsLocked();
316 }
317 } catch (PendingIntent.CanceledException e) {
318 return false;
319 }
320 }
321 return true;
322 }
323
324 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
325 if (mListener != null) {
326 try {
327 synchronized (this) {
328 // synchronize to ensure incrementPendingBroadcastsLocked()
329 // is called before decrementPendingBroadcasts()
330 if (enabled) {
331 mListener.onProviderEnabled(provider);
332 } else {
333 mListener.onProviderDisabled(provider);
334 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700335 // call this after broadcasting so we do not increment
336 // if we throw an exeption.
337 incrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700338 }
339 } catch (RemoteException e) {
340 return false;
341 }
342 } else {
343 Intent providerIntent = new Intent();
344 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
345 try {
346 synchronized (this) {
347 // synchronize to ensure incrementPendingBroadcastsLocked()
348 // is called before decrementPendingBroadcasts()
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700349 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
Nick Pellyf1be6862012-05-15 10:53:42 -0700350 mRequiredPermissions);
Mike Lockwood48f17512009-04-23 09:12:08 -0700351 // call this after broadcasting so we do not increment
352 // if we throw an exeption.
353 incrementPendingBroadcastsLocked();
354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355 } catch (PendingIntent.CanceledException e) {
356 return false;
357 }
358 }
359 return true;
360 }
361
Nick Pellyf1be6862012-05-15 10:53:42 -0700362 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700364 if (LOCAL_LOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800365 Slog.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400367 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800368 removeUpdatesLocked(this);
369 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700370 synchronized (this) {
371 if (mPendingBroadcasts > 0) {
372 LocationManagerService.this.decrementPendingBroadcasts();
373 mPendingBroadcasts = 0;
374 }
375 }
376 }
377
Nick Pellye0fd6932012-07-11 10:26:13 -0700378 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700379 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
380 int resultCode, String resultData, Bundle resultExtras) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400381 synchronized (this) {
382 decrementPendingBroadcastsLocked();
Mike Lockwood48f17512009-04-23 09:12:08 -0700383 }
384 }
385
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400386 // this must be called while synchronized by caller in a synchronized block
387 // containing the sending of the broadcaset
388 private void incrementPendingBroadcastsLocked() {
389 if (mPendingBroadcasts++ == 0) {
390 LocationManagerService.this.incrementPendingBroadcasts();
391 }
392 }
393
394 private void decrementPendingBroadcastsLocked() {
395 if (--mPendingBroadcasts == 0) {
396 LocationManagerService.this.decrementPendingBroadcasts();
Mike Lockwood48f17512009-04-23 09:12:08 -0700397 }
398 }
399 }
400
Nick Pellye0fd6932012-07-11 10:26:13 -0700401 @Override
Mike Lockwood48f17512009-04-23 09:12:08 -0700402 public void locationCallbackFinished(ILocationListener listener) {
Joshua Bartel080b61b2009-10-05 12:44:46 -0400403 //Do not use getReceiver here as that will add the ILocationListener to
404 //the receiver list if it is not found. If it is not found then the
405 //LocationListener was removed when it had a pending broadcast and should
406 //not be added back.
407 IBinder binder = listener.asBinder();
408 Receiver receiver = mReceivers.get(binder);
Mike Lockwood48f17512009-04-23 09:12:08 -0700409 if (receiver != null) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400410 synchronized (receiver) {
411 // so wakelock calls will succeed
412 long identity = Binder.clearCallingIdentity();
413 receiver.decrementPendingBroadcastsLocked();
414 Binder.restoreCallingIdentity(identity);
415 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 }
417 }
418
Mike Lockwood9637d472009-04-02 21:41:57 -0700419 private final class SettingsObserver implements Observer {
Nick Pellye0fd6932012-07-11 10:26:13 -0700420 @Override
Mike Lockwood9637d472009-04-02 21:41:57 -0700421 public void update(Observable o, Object arg) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400422 synchronized (mLock) {
Mike Lockwood9637d472009-04-02 21:41:57 -0700423 updateProvidersLocked();
424 }
425 }
426 }
427
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500428 private void addProvider(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400429 mProviders.add(provider);
430 mProvidersByName.put(provider.getName(), provider);
431 }
432
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500433 private void removeProvider(LocationProviderInterface provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400434 mProviders.remove(provider);
435 mProvidersByName.remove(provider.getName());
436 }
437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 private void loadProviders() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400439 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 if (sProvidersLoaded) {
441 return;
442 }
443
444 // Load providers
445 loadProvidersLocked();
446 sProvidersLoaded = true;
447 }
448 }
449
450 private void loadProvidersLocked() {
451 try {
452 _loadProvidersLocked();
453 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800454 Slog.e(TAG, "Exception loading providers:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 }
456 }
457
458 private void _loadProvidersLocked() {
459 // Attempt to load "real" providers first
460 if (GpsLocationProvider.isSupported()) {
461 // Create a gps location provider
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500462 GpsLocationProvider gpsProvider = new GpsLocationProvider(mContext, this);
463 mGpsStatusProvider = gpsProvider.getGpsStatusProvider();
464 mNetInitiatedListener = gpsProvider.getNetInitiatedListener();
465 addProvider(gpsProvider);
466 mGpsLocationProvider = gpsProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 }
468
Mike Lockwooda4903f22010-02-17 06:42:23 -0500469 // create a passive location provider, which is always enabled
470 PassiveProvider passiveProvider = new PassiveProvider(this);
471 addProvider(passiveProvider);
472 mEnabledProviders.add(passiveProvider.getName());
473
Nick Pelly00355d52012-05-27 16:12:45 -0700474 // initialize external network location and geocoder services.
475 // The initial value of mNetworkLocationProviderPackageName and
476 // mGeocodeProviderPackageName is just used to determine what
477 // signatures future mNetworkLocationProviderPackageName and
478 // mGeocodeProviderPackageName packages must have. So alternate
479 // providers can be installed under a different package name
480 // so long as they have the same signature as the original
481 // provider packages.
482 if (mNetworkLocationProviderPackageName != null) {
483 String packageName = findBestPackage(LocationProviderProxy.SERVICE_ACTION,
484 mNetworkLocationProviderPackageName);
485 if (packageName != null) {
486 mNetworkLocationProvider = new LocationProviderProxy(mContext,
487 LocationManager.NETWORK_PROVIDER,
488 packageName, mLocationHandler);
489 mNetworkLocationProviderPackageName = packageName;
490 addProvider(mNetworkLocationProvider);
491 }
Mike Lockwood628fd6d2010-01-25 22:46:13 -0500492 }
Nick Pelly00355d52012-05-27 16:12:45 -0700493 if (mGeocodeProviderPackageName != null) {
494 String packageName = findBestPackage(GeocoderProxy.SERVICE_ACTION,
495 mGeocodeProviderPackageName);
496 if (packageName != null) {
497 mGeocodeProvider = new GeocoderProxy(mContext, packageName);
498 mGeocodeProviderPackageName = packageName;
499 }
Mike Lockwood628fd6d2010-01-25 22:46:13 -0500500 }
501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 updateProvidersLocked();
503 }
504
505 /**
Nick Pelly00355d52012-05-27 16:12:45 -0700506 * Pick the best (network location provider or geocode provider) package.
507 * The best package:
508 * - implements serviceIntentName
509 * - has signatures that match that of sigPackageName
510 * - has the highest version value in a meta-data field in the service component
511 */
512 String findBestPackage(String serviceIntentName, String sigPackageName) {
513 Intent intent = new Intent(serviceIntentName);
514 List<ResolveInfo> infos = mPackageManager.queryIntentServices(intent,
515 PackageManager.GET_META_DATA);
516 if (infos == null) return null;
517
518 int bestVersion = Integer.MIN_VALUE;
519 String bestPackage = null;
520 for (ResolveInfo info : infos) {
521 String packageName = info.serviceInfo.packageName;
522 // check signature
523 if (mPackageManager.checkSignatures(packageName, sigPackageName) !=
524 PackageManager.SIGNATURE_MATCH) {
525 Slog.w(TAG, packageName + " implements " + serviceIntentName +
526 " but its signatures don't match those in " + sigPackageName +
527 ", ignoring");
528 continue;
529 }
530 // read version
531 int version = 0;
532 if (info.serviceInfo.metaData != null) {
533 version = info.serviceInfo.metaData.getInt("version", 0);
534 }
535 if (LOCAL_LOGV) Slog.v(TAG, packageName + " implements " + serviceIntentName +
536 " with version " + version);
537 if (version > bestVersion) {
538 bestVersion = version;
539 bestPackage = packageName;
540 }
541 }
542
543 return bestPackage;
544 }
545
546 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 * @param context the context that the LocationManagerService runs in
548 */
549 public LocationManagerService(Context context) {
550 super();
551 mContext = context;
Mike Lockwoode97ae402010-09-29 15:23:46 -0400552 Resources resources = context.getResources();
Nick Pelly00355d52012-05-27 16:12:45 -0700553
Mike Lockwoode97ae402010-09-29 15:23:46 -0400554 mNetworkLocationProviderPackageName = resources.getString(
Nick Pelly00355d52012-05-27 16:12:45 -0700555 com.android.internal.R.string.config_networkLocationProviderPackageName);
Mike Lockwoode97ae402010-09-29 15:23:46 -0400556 mGeocodeProviderPackageName = resources.getString(
Nick Pelly00355d52012-05-27 16:12:45 -0700557 com.android.internal.R.string.config_geocodeProviderPackageName);
558
Dianne Hackbornd0d75032012-04-19 23:12:09 -0700559 mPackageMonitor.register(context, null, true);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700560
The Android Open Source Project10592532009-03-18 17:39:46 -0700561 if (LOCAL_LOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800562 Slog.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 }
Mike Lockwood3d12b512009-04-21 23:25:35 -0700564 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565
Mike Lockwood46db5042010-02-22 16:36:44 -0500566 void systemReady() {
Nick Pellye0fd6932012-07-11 10:26:13 -0700567 // we defer starting up the service until the system is ready
Mike Lockwood46db5042010-02-22 16:36:44 -0500568 Thread thread = new Thread(null, this, "LocationManagerService");
569 thread.start();
570 }
571
Mike Lockwood3d12b512009-04-21 23:25:35 -0700572 private void initialize() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 // Create a wake lock, needs to be done before calling loadProviders() below
574 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
575 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
Nick Pelly00355d52012-05-27 16:12:45 -0700576 mPackageManager = mContext.getPackageManager();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800578 // Load providers
579 loadProviders();
580
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 // Register for Network (Wifi or Mobile) updates
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582 IntentFilter intentFilter = new IntentFilter();
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400583 intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
584 // Register for Package Manager updates
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800585 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
586 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Dianne Hackborn21f1bd12010-02-19 17:02:21 -0800587 intentFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
Mike Lockwood0528b9b2009-05-07 10:12:54 -0400588 mContext.registerReceiver(mBroadcastReceiver, intentFilter);
Suchi Amalapurapub56ae202010-02-04 22:51:07 -0800589 IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -0800590 mContext.registerReceiver(mBroadcastReceiver, sdFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591
Mike Lockwood9637d472009-04-02 21:41:57 -0700592 // listen for settings changes
593 ContentResolver resolver = mContext.getContentResolver();
594 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
Nick Pellye0fd6932012-07-11 10:26:13 -0700595 "(" + NameValueTable.NAME + "=?)",
Mike Lockwood9637d472009-04-02 21:41:57 -0700596 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
597 null);
Nick Pellye0fd6932012-07-11 10:26:13 -0700598 mSettings = new ContentQueryMap(settingsCursor, NameValueTable.NAME, true, mLocationHandler);
Mike Lockwood9637d472009-04-02 21:41:57 -0700599 SettingsObserver settingsObserver = new SettingsObserver();
600 mSettings.addObserver(settingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800601 }
602
Nick Pellye0fd6932012-07-11 10:26:13 -0700603 @Override
Mike Lockwood3d12b512009-04-21 23:25:35 -0700604 public void run()
605 {
606 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
607 Looper.prepare();
608 mLocationHandler = new LocationWorkerHandler();
609 initialize();
Nick Pellye0fd6932012-07-11 10:26:13 -0700610 mGeofenceManager = new GeofenceManager(mContext);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700611 Looper.loop();
612 }
613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 private boolean isAllowedBySettingsLocked(String provider) {
615 if (mEnabledProviders.contains(provider)) {
616 return true;
617 }
618 if (mDisabledProviders.contains(provider)) {
619 return false;
620 }
621 // Use system settings
622 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623
Brad Larson8eb3ea62009-12-29 11:47:55 -0600624 return Settings.Secure.isLocationProviderEnabled(resolver, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 }
626
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700627 private String checkPermissionsSafe(String provider, String lastPermission) {
628 if (LocationManager.GPS_PROVIDER.equals(provider)
629 || LocationManager.PASSIVE_PROVIDER.equals(provider)) {
630 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
631 != PackageManager.PERMISSION_GRANTED) {
632 throw new SecurityException("Provider " + provider
633 + " requires ACCESS_FINE_LOCATION permission");
634 }
635 return ACCESS_FINE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700637
638 // Assume any other provider requires the coarse or fine permission.
639 if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
640 == PackageManager.PERMISSION_GRANTED) {
641 return ACCESS_FINE_LOCATION.equals(lastPermission)
642 ? lastPermission : ACCESS_COARSE_LOCATION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
Dianne Hackborn6c418d52011-06-29 14:05:33 -0700644 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
645 == PackageManager.PERMISSION_GRANTED) {
646 return ACCESS_FINE_LOCATION;
647 }
648
649 throw new SecurityException("Provider " + provider
650 + " requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 }
652
653 private boolean isAllowedProviderSafe(String provider) {
Bryan Mawhinney43cc4692010-02-18 13:00:16 +0000654 if ((LocationManager.GPS_PROVIDER.equals(provider)
655 || LocationManager.PASSIVE_PROVIDER.equals(provider))
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400656 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800657 != PackageManager.PERMISSION_GRANTED)) {
658 return false;
659 }
660 if (LocationManager.NETWORK_PROVIDER.equals(provider)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400661 && (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 != PackageManager.PERMISSION_GRANTED)
Mike Lockwoodb7e99222009-07-07 13:18:21 -0400663 && (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 != PackageManager.PERMISSION_GRANTED)) {
665 return false;
666 }
667
668 return true;
669 }
670
Nick Pellye0fd6932012-07-11 10:26:13 -0700671 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800672 public List<String> getAllProviders() {
673 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400674 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 return _getAllProvidersLocked();
676 }
677 } catch (SecurityException se) {
678 throw se;
679 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800680 Slog.e(TAG, "getAllProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800681 return null;
682 }
683 }
684
685 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700686 if (LOCAL_LOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800687 Slog.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400689 ArrayList<String> out = new ArrayList<String>(mProviders.size());
690 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500691 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 out.add(p.getName());
693 }
694 return out;
695 }
696
Nick Pellye0fd6932012-07-11 10:26:13 -0700697 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700698 public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400700 synchronized (mLock) {
Mike Lockwood03ca2162010-04-01 08:10:09 -0700701 return _getProvidersLocked(criteria, enabledOnly);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800702 }
703 } catch (SecurityException se) {
704 throw se;
705 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800706 Slog.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800707 return null;
708 }
709 }
710
Mike Lockwood03ca2162010-04-01 08:10:09 -0700711 private List<String> _getProvidersLocked(Criteria criteria, boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700712 if (LOCAL_LOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800713 Slog.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400715 ArrayList<String> out = new ArrayList<String>(mProviders.size());
716 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500717 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 String name = p.getName();
719 if (isAllowedProviderSafe(name)) {
720 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
721 continue;
722 }
Mike Lockwood03ca2162010-04-01 08:10:09 -0700723 if (criteria != null && !p.meetsCriteria(criteria)) {
724 continue;
725 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800726 out.add(name);
727 }
728 }
729 return out;
730 }
731
Mike Lockwood03ca2162010-04-01 08:10:09 -0700732 /**
733 * Returns the next looser power requirement, in the sequence:
734 *
735 * POWER_LOW -> POWER_MEDIUM -> POWER_HIGH -> NO_REQUIREMENT
736 */
737 private int nextPower(int power) {
738 switch (power) {
739 case Criteria.POWER_LOW:
740 return Criteria.POWER_MEDIUM;
741 case Criteria.POWER_MEDIUM:
742 return Criteria.POWER_HIGH;
743 case Criteria.POWER_HIGH:
744 return Criteria.NO_REQUIREMENT;
745 case Criteria.NO_REQUIREMENT:
746 default:
747 return Criteria.NO_REQUIREMENT;
748 }
749 }
750
751 /**
752 * Returns the next looser accuracy requirement, in the sequence:
753 *
754 * ACCURACY_FINE -> ACCURACY_APPROXIMATE-> NO_REQUIREMENT
755 */
756 private int nextAccuracy(int accuracy) {
757 if (accuracy == Criteria.ACCURACY_FINE) {
758 return Criteria.ACCURACY_COARSE;
759 } else {
760 return Criteria.NO_REQUIREMENT;
761 }
762 }
763
764 private class LpPowerComparator implements Comparator<LocationProviderInterface> {
Nick Pellye0fd6932012-07-11 10:26:13 -0700765 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700766 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
767 // Smaller is better
768 return (l1.getPowerRequirement() - l2.getPowerRequirement());
769 }
770
771 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
772 return (l1.getPowerRequirement() == l2.getPowerRequirement());
773 }
774 }
775
776 private class LpAccuracyComparator implements Comparator<LocationProviderInterface> {
Nick Pellye0fd6932012-07-11 10:26:13 -0700777 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700778 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
779 // Smaller is better
780 return (l1.getAccuracy() - l2.getAccuracy());
781 }
782
783 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
784 return (l1.getAccuracy() == l2.getAccuracy());
785 }
786 }
787
788 private class LpCapabilityComparator implements Comparator<LocationProviderInterface> {
789
790 private static final int ALTITUDE_SCORE = 4;
791 private static final int BEARING_SCORE = 4;
792 private static final int SPEED_SCORE = 4;
793
794 private int score(LocationProviderInterface p) {
795 return (p.supportsAltitude() ? ALTITUDE_SCORE : 0) +
796 (p.supportsBearing() ? BEARING_SCORE : 0) +
797 (p.supportsSpeed() ? SPEED_SCORE : 0);
798 }
799
Nick Pellye0fd6932012-07-11 10:26:13 -0700800 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700801 public int compare(LocationProviderInterface l1, LocationProviderInterface l2) {
802 return (score(l2) - score(l1)); // Bigger is better
803 }
804
805 public boolean equals(LocationProviderInterface l1, LocationProviderInterface l2) {
806 return (score(l1) == score(l2));
807 }
808 }
809
810 private LocationProviderInterface best(List<String> providerNames) {
811 ArrayList<LocationProviderInterface> providers;
812 synchronized (mLock) {
Mike Lockwood9e3191d2010-10-26 10:01:55 -0400813 providers = new ArrayList<LocationProviderInterface>(providerNames.size());
814 for (String name : providerNames) {
815 providers.add(mProvidersByName.get(name));
Mike Lockwood03ca2162010-04-01 08:10:09 -0700816 }
817 }
818
819 if (providers.size() < 2) {
820 return providers.get(0);
821 }
822
823 // First, sort by power requirement
824 Collections.sort(providers, new LpPowerComparator());
825 int power = providers.get(0).getPowerRequirement();
826 if (power < providers.get(1).getPowerRequirement()) {
827 return providers.get(0);
828 }
829
830 int idx, size;
831
832 ArrayList<LocationProviderInterface> tmp = new ArrayList<LocationProviderInterface>();
833 idx = 0;
834 size = providers.size();
835 while ((idx < size) && (providers.get(idx).getPowerRequirement() == power)) {
836 tmp.add(providers.get(idx));
837 idx++;
838 }
839
840 // Next, sort by accuracy
841 Collections.sort(tmp, new LpAccuracyComparator());
842 int acc = tmp.get(0).getAccuracy();
843 if (acc < tmp.get(1).getAccuracy()) {
844 return tmp.get(0);
845 }
846
847 ArrayList<LocationProviderInterface> tmp2 = new ArrayList<LocationProviderInterface>();
848 idx = 0;
849 size = tmp.size();
850 while ((idx < size) && (tmp.get(idx).getAccuracy() == acc)) {
851 tmp2.add(tmp.get(idx));
852 idx++;
853 }
854
855 // Finally, sort by capability "score"
856 Collections.sort(tmp2, new LpCapabilityComparator());
857 return tmp2.get(0);
858 }
859
860 /**
861 * Returns the name of the provider that best meets the given criteria. Only providers
862 * that are permitted to be accessed by the calling activity will be
863 * returned. If several providers meet the criteria, the one with the best
864 * accuracy is returned. If no provider meets the criteria,
865 * the criteria are loosened in the following sequence:
866 *
867 * <ul>
868 * <li> power requirement
869 * <li> accuracy
870 * <li> bearing
871 * <li> speed
872 * <li> altitude
873 * </ul>
874 *
875 * <p> Note that the requirement on monetary cost is not removed
876 * in this process.
877 *
878 * @param criteria the criteria that need to be matched
879 * @param enabledOnly if true then only a provider that is currently enabled is returned
880 * @return name of the provider that best matches the requirements
881 */
Nick Pellye0fd6932012-07-11 10:26:13 -0700882 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700883 public String getBestProvider(Criteria criteria, boolean enabledOnly) {
884 List<String> goodProviders = getProviders(criteria, enabledOnly);
885 if (!goodProviders.isEmpty()) {
886 return best(goodProviders).getName();
887 }
888
889 // Make a copy of the criteria that we can modify
890 criteria = new Criteria(criteria);
891
892 // Loosen power requirement
893 int power = criteria.getPowerRequirement();
894 while (goodProviders.isEmpty() && (power != Criteria.NO_REQUIREMENT)) {
895 power = nextPower(power);
896 criteria.setPowerRequirement(power);
897 goodProviders = getProviders(criteria, enabledOnly);
898 }
899 if (!goodProviders.isEmpty()) {
900 return best(goodProviders).getName();
901 }
902
903 // Loosen accuracy requirement
904 int accuracy = criteria.getAccuracy();
905 while (goodProviders.isEmpty() && (accuracy != Criteria.NO_REQUIREMENT)) {
906 accuracy = nextAccuracy(accuracy);
907 criteria.setAccuracy(accuracy);
908 goodProviders = getProviders(criteria, enabledOnly);
909 }
910 if (!goodProviders.isEmpty()) {
911 return best(goodProviders).getName();
912 }
913
914 // Remove bearing requirement
915 criteria.setBearingRequired(false);
916 goodProviders = getProviders(criteria, enabledOnly);
917 if (!goodProviders.isEmpty()) {
918 return best(goodProviders).getName();
919 }
920
921 // Remove speed requirement
922 criteria.setSpeedRequired(false);
923 goodProviders = getProviders(criteria, enabledOnly);
924 if (!goodProviders.isEmpty()) {
925 return best(goodProviders).getName();
926 }
927
928 // Remove altitude requirement
929 criteria.setAltitudeRequired(false);
930 goodProviders = getProviders(criteria, enabledOnly);
931 if (!goodProviders.isEmpty()) {
932 return best(goodProviders).getName();
933 }
934
935 return null;
936 }
937
Nick Pellye0fd6932012-07-11 10:26:13 -0700938 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -0700939 public boolean providerMeetsCriteria(String provider, Criteria criteria) {
940 LocationProviderInterface p = mProvidersByName.get(provider);
941 if (p == null) {
942 throw new IllegalArgumentException("provider=" + provider);
943 }
944 return p.meetsCriteria(criteria);
945 }
946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800947 private void updateProvidersLocked() {
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700948 boolean changesMade = false;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400949 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500950 LocationProviderInterface p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800951 boolean isEnabled = p.isEnabled();
952 String name = p.getName();
953 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800954 if (isEnabled && !shouldBeEnabled) {
955 updateProviderListenersLocked(name, false);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700956 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 } else if (!isEnabled && shouldBeEnabled) {
958 updateProviderListenersLocked(name, true);
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700959 changesMade = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800960 }
Brad Fitzpatrick0c5a0402010-08-27 14:01:23 -0700961 }
962 if (changesMade) {
963 mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800964 }
965 }
966
967 private void updateProviderListenersLocked(String provider, boolean enabled) {
968 int listeners = 0;
969
Mike Lockwoodd03ff942010-02-09 08:46:14 -0500970 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800971 if (p == null) {
972 return;
973 }
974
975 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -0700976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
978 if (records != null) {
979 final int N = records.size();
980 for (int i=0; i<N; i++) {
981 UpdateRecord record = records.get(i);
982 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700983 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
984 if (deadReceivers == null) {
985 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 }
Simon Schoar46866572009-06-10 21:12:10 +0200987 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 }
989 listeners++;
990 }
991 }
992
993 if (deadReceivers != null) {
994 for (int i=deadReceivers.size()-1; i>=0; i--) {
995 removeUpdatesLocked(deadReceivers.get(i));
996 }
997 }
Nick Pellye0fd6932012-07-11 10:26:13 -0700998
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 if (enabled) {
1000 p.enable();
1001 if (listeners > 0) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001002 p.setMinTime(getMinTimeLocked(provider), mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 p.enableLocationTracking(true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001004 }
1005 } else {
1006 p.enableLocationTracking(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 p.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001008 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
1010
1011 private long getMinTimeLocked(String provider) {
1012 long minTime = Long.MAX_VALUE;
1013 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001014 mTmpWorkSource.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 if (records != null) {
1016 for (int i=records.size()-1; i>=0; i--) {
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001017 UpdateRecord ur = records.get(i);
1018 long curTime = ur.mMinTime;
1019 if (curTime < minTime) {
1020 minTime = curTime;
1021 }
1022 }
1023 long inclTime = (minTime*3)/2;
1024 for (int i=records.size()-1; i>=0; i--) {
1025 UpdateRecord ur = records.get(i);
1026 if (ur.mMinTime <= inclTime) {
1027 mTmpWorkSource.add(ur.mUid);
1028 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001029 }
1030 }
1031 return minTime;
1032 }
1033
1034 private class UpdateRecord {
1035 final String mProvider;
1036 final Receiver mReceiver;
1037 final long mMinTime;
1038 final float mMinDistance;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001039 final boolean mSingleShot;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001040 final int mUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001041 Location mLastFixBroadcast;
1042 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043
1044 /**
1045 * Note: must be constructed with lock held.
1046 */
Mike Lockwood03ca2162010-04-01 08:10:09 -07001047 UpdateRecord(String provider, long minTime, float minDistance, boolean singleShot,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001048 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 mProvider = provider;
1050 mReceiver = receiver;
1051 mMinTime = minTime;
1052 mMinDistance = minDistance;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001053 mSingleShot = singleShot;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001055
1056 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1057 if (records == null) {
1058 records = new ArrayList<UpdateRecord>();
1059 mRecordsByProvider.put(provider, records);
1060 }
1061 if (!records.contains(this)) {
1062 records.add(this);
1063 }
1064 }
1065
1066 /**
1067 * Method to be called when a record will no longer be used. Calling this multiple times
1068 * must have the same effect as calling it once.
1069 */
1070 void disposeLocked() {
1071 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
Mike Lockwood3a76fd62009-09-01 07:26:56 -04001072 if (records != null) {
1073 records.remove(this);
1074 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 }
1076
1077 @Override
1078 public String toString() {
1079 return "UpdateRecord{"
1080 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001081 + " mProvider: " + mProvider + " mUid: " + mUid + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001082 }
Nick Pellyf1be6862012-05-15 10:53:42 -07001083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001084 void dump(PrintWriter pw, String prefix) {
1085 pw.println(prefix + this);
1086 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
1087 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001088 pw.println(prefix + "mSingleShot=" + mSingleShot);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001089 pw.println(prefix + "mUid=" + mUid);
1090 pw.println(prefix + "mLastFixBroadcast:");
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06001091 if (mLastFixBroadcast != null) {
1092 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
1093 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001094 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 }
1097
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001098 private Receiver getReceiver(ILocationListener listener) {
1099 IBinder binder = listener.asBinder();
1100 Receiver receiver = mReceivers.get(binder);
1101 if (receiver == null) {
1102 receiver = new Receiver(listener);
1103 mReceivers.put(binder, receiver);
1104
1105 try {
1106 if (receiver.isListener()) {
1107 receiver.getListener().asBinder().linkToDeath(receiver, 0);
1108 }
1109 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001110 Slog.e(TAG, "linkToDeath failed:", e);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001111 return null;
1112 }
1113 }
1114 return receiver;
1115 }
1116
1117 private Receiver getReceiver(PendingIntent intent) {
1118 Receiver receiver = mReceivers.get(intent);
1119 if (receiver == null) {
1120 receiver = new Receiver(intent);
1121 mReceivers.put(intent, receiver);
1122 }
1123 return receiver;
1124 }
1125
1126 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
1127 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1128 if (records != null) {
1129 for (int i = records.size() - 1; i >= 0; i--) {
1130 UpdateRecord record = records.get(i);
1131 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
1132 return true;
1133 }
1134 }
1135 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001136 return false;
1137 }
1138
Nick Pellye0fd6932012-07-11 10:26:13 -07001139 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001140 public void requestLocationUpdates(String provider, Criteria criteria,
1141 long minTime, float minDistance, boolean singleShot, ILocationListener listener) {
1142 if (criteria != null) {
1143 // FIXME - should we consider using multiple providers simultaneously
1144 // rather than only the best one?
1145 // Should we do anything different for single shot fixes?
1146 provider = getBestProvider(criteria, true);
1147 if (provider == null) {
1148 throw new IllegalArgumentException("no providers found for criteria");
1149 }
1150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001152 synchronized (mLock) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001153 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1154 getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 }
1156 } catch (SecurityException se) {
1157 throw se;
Mike Lockwood3b9ef082010-03-02 10:33:55 -05001158 } catch (IllegalArgumentException iae) {
1159 throw iae;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001161 Slog.e(TAG, "requestUpdates got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001162 }
1163 }
1164
Nick Pellye0fd6932012-07-11 10:26:13 -07001165 void validatePackageName(int uid, String packageName) {
1166 if (packageName == null) {
1167 throw new SecurityException("packageName cannot be null");
1168 }
1169 String[] packages = mPackageManager.getPackagesForUid(uid);
1170 if (packages == null) {
1171 throw new SecurityException("invalid UID " + uid);
1172 }
1173 for (String pkg : packages) {
1174 if (packageName.equals(pkg)) return;
1175 }
1176 throw new SecurityException("invalid package name");
1177 }
1178
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001179 void validatePendingIntent(PendingIntent intent) {
1180 if (intent.isTargetedToPackage()) {
1181 return;
1182 }
1183 Slog.i(TAG, "Given Intent does not require a specific package: "
1184 + intent);
1185 // XXX we should really throw a security exception, if the caller's
1186 // targetSdkVersion is high enough.
1187 //throw new SecurityException("Given Intent does not require a specific package: "
1188 // + intent);
1189 }
1190
Nick Pellye0fd6932012-07-11 10:26:13 -07001191 @Override
Mike Lockwood03ca2162010-04-01 08:10:09 -07001192 public void requestLocationUpdatesPI(String provider, Criteria criteria,
1193 long minTime, float minDistance, boolean singleShot, PendingIntent intent) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001194 validatePendingIntent(intent);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001195 if (criteria != null) {
1196 // FIXME - should we consider using multiple providers simultaneously
1197 // rather than only the best one?
1198 // Should we do anything different for single shot fixes?
1199 provider = getBestProvider(criteria, true);
1200 if (provider == null) {
1201 throw new IllegalArgumentException("no providers found for criteria");
1202 }
1203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001204 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001205 synchronized (mLock) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001206 requestLocationUpdatesLocked(provider, minTime, minDistance, singleShot,
1207 getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001208 }
1209 } catch (SecurityException se) {
1210 throw se;
Mike Lockwood3b9ef082010-03-02 10:33:55 -05001211 } catch (IllegalArgumentException iae) {
1212 throw iae;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001214 Slog.e(TAG, "requestUpdates got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 }
1216 }
1217
Mike Lockwood03ca2162010-04-01 08:10:09 -07001218 private void requestLocationUpdatesLocked(String provider, long minTime, float minDistance,
1219 boolean singleShot, Receiver receiver) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001221 LocationProviderInterface p = mProvidersByName.get(provider);
1222 if (p == null) {
Nick Pellyf1be6862012-05-15 10:53:42 -07001223 throw new IllegalArgumentException("requested provider " + provider +
1224 " doesn't exisit");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 }
Nick Pellyf1be6862012-05-15 10:53:42 -07001226 receiver.mRequiredPermissions = checkPermissionsSafe(provider,
1227 receiver.mRequiredPermissions);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001229 // so wakelock calls will succeed
Nick Pelly6e4cb6a2012-05-04 13:29:20 -07001230 final int callingPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001231 final int callingUid = Binder.getCallingUid();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001232 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001233 long identity = Binder.clearCallingIdentity();
1234 try {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001235 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, singleShot,
1236 receiver, callingUid);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001237 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001238 if (oldRecord != null) {
1239 oldRecord.disposeLocked();
1240 }
1241
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001242 if (newUid) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001243 p.addListener(callingUid);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001244 }
1245
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001246 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1247 if (isProviderEnabled) {
1248 long minTimeForProvider = getMinTimeLocked(provider);
Nick Pelly6e4cb6a2012-05-04 13:29:20 -07001249 Slog.i(TAG, "request " + provider + " (pid " + callingPid + ") " + minTime +
1250 " " + minTimeForProvider + (singleShot ? " (singleshot)" : ""));
Dianne Hackborn7e9f4eb2010-09-10 18:43:00 -07001251 p.setMinTime(minTimeForProvider, mTmpWorkSource);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001252 // try requesting single shot if singleShot is true, and fall back to
1253 // regular location tracking if requestSingleShotFix() is not supported
1254 if (!singleShot || !p.requestSingleShotFix()) {
1255 p.enableLocationTracking(true);
1256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 } else {
Mike Lockwood48f17512009-04-23 09:12:08 -07001258 // Notify the listener that updates are currently disabled
1259 receiver.callProviderEnabledLocked(provider, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001260 }
Mike Lockwood2d4d1bf2010-10-18 17:06:26 -04001261 if (LOCAL_LOGV) {
1262 Slog.v(TAG, "_requestLocationUpdates: provider = " + provider + " listener = " + receiver);
1263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 } finally {
1265 Binder.restoreCallingIdentity(identity);
1266 }
1267 }
1268
Nick Pellye0fd6932012-07-11 10:26:13 -07001269 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001270 public void removeUpdates(ILocationListener listener) {
1271 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001272 synchronized (mLock) {
1273 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 } catch (SecurityException se) {
1276 throw se;
Mike Lockwood3b9ef082010-03-02 10:33:55 -05001277 } catch (IllegalArgumentException iae) {
1278 throw iae;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001279 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001280 Slog.e(TAG, "removeUpdates got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 }
1282 }
1283
Nick Pellye0fd6932012-07-11 10:26:13 -07001284 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001285 public void removeUpdatesPI(PendingIntent intent) {
1286 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001287 synchronized (mLock) {
1288 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001289 }
1290 } catch (SecurityException se) {
1291 throw se;
Mike Lockwood3b9ef082010-03-02 10:33:55 -05001292 } catch (IllegalArgumentException iae) {
1293 throw iae;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001294 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001295 Slog.e(TAG, "removeUpdates got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 }
1297 }
1298
1299 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001300 if (LOCAL_LOGV) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001301 Slog.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 }
1303
1304 // so wakelock calls will succeed
Nick Pelly6e4cb6a2012-05-04 13:29:20 -07001305 final int callingPid = Binder.getCallingPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001306 final int callingUid = Binder.getCallingUid();
1307 long identity = Binder.clearCallingIdentity();
1308 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001309 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1310 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
Joshua Bartel080b61b2009-10-05 12:44:46 -04001311 synchronized(receiver) {
1312 if(receiver.mPendingBroadcasts > 0) {
1313 decrementPendingBroadcasts();
1314 receiver.mPendingBroadcasts = 0;
1315 }
1316 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 }
1318
1319 // Record which providers were associated with this listener
1320 HashSet<String> providers = new HashSet<String>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001321 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 if (oldRecords != null) {
1323 // Call dispose() on the obsolete update records.
1324 for (UpdateRecord record : oldRecords.values()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001325 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001326 LocationProviderInterface p = mProvidersByName.get(record.mProvider);
1327 if (p != null) {
1328 p.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001329 }
1330 }
1331 record.disposeLocked();
1332 }
1333 // Accumulate providers
1334 providers.addAll(oldRecords.keySet());
1335 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001336
1337 // See if the providers associated with this listener have any
1338 // other listeners; if one does, inform it of the new smallest minTime
1339 // value; if one does not, disable location tracking for it
1340 for (String provider : providers) {
1341 // If provider is already disabled, don't need to do anything
1342 if (!isAllowedBySettingsLocked(provider)) {
1343 continue;
1344 }
1345
1346 boolean hasOtherListener = false;
1347 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1348 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1349 hasOtherListener = true;
1350 }
1351
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001352 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001353 if (p != null) {
1354 if (hasOtherListener) {
Nick Pelly6e4cb6a2012-05-04 13:29:20 -07001355 long minTime = getMinTimeLocked(provider);
1356 Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1357 "), next minTime = " + minTime);
1358 p.setMinTime(minTime, mTmpWorkSource);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001359 } else {
Nick Pelly6e4cb6a2012-05-04 13:29:20 -07001360 Slog.i(TAG, "remove " + provider + " (pid " + callingPid +
1361 "), disabled");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001362 p.enableLocationTracking(false);
1363 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 }
1365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 } finally {
1367 Binder.restoreCallingIdentity(identity);
1368 }
1369 }
1370
Nick Pellye0fd6932012-07-11 10:26:13 -07001371 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001373 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001374 return false;
1375 }
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001376 if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001377 PackageManager.PERMISSION_GRANTED) {
1378 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1379 }
1380
1381 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001382 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001384 Slog.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001385 return false;
1386 }
1387 return true;
1388 }
1389
Nick Pellye0fd6932012-07-11 10:26:13 -07001390 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001392 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001393 try {
1394 mGpsStatusProvider.removeGpsStatusListener(listener);
1395 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001396 Slog.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 }
1399 }
1400
Nick Pellye0fd6932012-07-11 10:26:13 -07001401 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
Mike Lockwoodc6cc8362009-08-17 13:16:08 -04001403 if (provider == null) {
1404 // throw NullPointerException to remain compatible with previous implementation
1405 throw new NullPointerException();
1406 }
1407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 // first check for permission to the provider
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001409 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
Mike Lockwoodb7e99222009-07-07 13:18:21 -04001411 if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 != PackageManager.PERMISSION_GRANTED)) {
1413 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1414 }
1415
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001416 synchronized (mLock) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001417 LocationProviderInterface p = mProvidersByName.get(provider);
1418 if (p == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 return false;
1420 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001421
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001422 return p.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 }
1424 }
1425
Nick Pellye0fd6932012-07-11 10:26:13 -07001426 @Override
Danke Xie22d1f9f2009-08-18 18:28:45 -04001427 public boolean sendNiResponse(int notifId, int userResponse)
1428 {
Mike Lockwood18ad9f62009-08-27 14:01:23 -07001429 if (Binder.getCallingUid() != Process.myUid()) {
1430 throw new SecurityException(
1431 "calling sendNiResponse from outside of the system is not allowed");
1432 }
Danke Xie22d1f9f2009-08-18 18:28:45 -04001433 try {
1434 return mNetInitiatedListener.sendNiResponse(notifId, userResponse);
1435 }
1436 catch (RemoteException e)
1437 {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001438 Slog.e(TAG, "RemoteException in LocationManagerService.sendNiResponse");
Danke Xie22d1f9f2009-08-18 18:28:45 -04001439 return false;
1440 }
1441 }
1442
Nick Pellye0fd6932012-07-11 10:26:13 -07001443 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001444 public void addProximityAlert(double latitude, double longitude,
Nick Pellye0fd6932012-07-11 10:26:13 -07001445 float radius, long expiration, PendingIntent intent, String packageName) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001446 validatePendingIntent(intent);
Nick Pellye0fd6932012-07-11 10:26:13 -07001447 validatePackageName(Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448
1449 // Require ability to access all providers for now
1450 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1451 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1452 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1453 }
1454
Nick Pellye0fd6932012-07-11 10:26:13 -07001455 if (LOCAL_LOGV) Slog.v(TAG, "addProximityAlert: lat=" + latitude + ", long=" + longitude +
1456 ", radius=" + radius + ", exp=" + expiration + ", intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457
Nick Pellye0fd6932012-07-11 10:26:13 -07001458 mGeofenceManager.addFence(latitude, longitude, radius, expiration, intent,
1459 Binder.getCallingUid(), packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001460 }
1461
Nick Pellye0fd6932012-07-11 10:26:13 -07001462 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001463 public void removeProximityAlert(PendingIntent intent) {
Nick Pellye0fd6932012-07-11 10:26:13 -07001464 if (intent == null) throw new NullPointerException("pending intent is null");
1465
1466 if (LOCAL_LOGV) Slog.v(TAG, "removeProximityAlert: intent = " + intent);
1467
1468 mGeofenceManager.removeFence(intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001469 }
1470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001471 /**
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001472 * @return null if the provider does not exist
Alexey Tarasovf2db9fb2009-09-01 02:37:07 +11001473 * @throws SecurityException if the provider is not allowed to be
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001474 * accessed by the caller
1475 */
Nick Pellye0fd6932012-07-11 10:26:13 -07001476 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 public Bundle getProviderInfo(String provider) {
1478 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001479 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001480 return _getProviderInfoLocked(provider);
1481 }
1482 } catch (SecurityException se) {
1483 throw se;
Mike Lockwood3b9ef082010-03-02 10:33:55 -05001484 } catch (IllegalArgumentException iae) {
1485 throw iae;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001486 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001487 Slog.e(TAG, "_getProviderInfo got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001488 return null;
1489 }
1490 }
1491
1492 private Bundle _getProviderInfoLocked(String provider) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001493 LocationProviderInterface p = mProvidersByName.get(provider);
Mike Lockwood223e84d2010-03-12 07:51:06 -05001494 if (p == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001495 return null;
1496 }
1497
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001498 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499
1500 Bundle b = new Bundle();
1501 b.putBoolean("network", p.requiresNetwork());
1502 b.putBoolean("satellite", p.requiresSatellite());
1503 b.putBoolean("cell", p.requiresCell());
1504 b.putBoolean("cost", p.hasMonetaryCost());
1505 b.putBoolean("altitude", p.supportsAltitude());
1506 b.putBoolean("speed", p.supportsSpeed());
1507 b.putBoolean("bearing", p.supportsBearing());
1508 b.putInt("power", p.getPowerRequirement());
1509 b.putInt("accuracy", p.getAccuracy());
1510
1511 return b;
1512 }
1513
Nick Pellye0fd6932012-07-11 10:26:13 -07001514 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 public boolean isProviderEnabled(String provider) {
1516 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001517 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 return _isProviderEnabledLocked(provider);
1519 }
1520 } catch (SecurityException se) {
1521 throw se;
1522 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001523 Slog.e(TAG, "isProviderEnabled got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 return false;
1525 }
1526 }
1527
Nick Pellye0fd6932012-07-11 10:26:13 -07001528 @Override
Mike Lockwooda4903f22010-02-17 06:42:23 -05001529 public void reportLocation(Location location, boolean passive) {
Mike Lockwood275555c2009-05-01 11:30:34 -04001530 if (mContext.checkCallingOrSelfPermission(INSTALL_LOCATION_PROVIDER)
1531 != PackageManager.PERMISSION_GRANTED) {
1532 throw new SecurityException("Requires INSTALL_LOCATION_PROVIDER permission");
1533 }
1534
Nick Pelly2eeeec22012-07-18 13:13:37 -07001535 if (!location.isComplete()) {
1536 Log.w(TAG, "Dropping incomplete location: " + location);
1537 return;
1538 }
1539
Mike Lockwood4e50b782009-04-03 08:24:43 -07001540 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1541 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001542 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001543 mLocationHandler.sendMessageAtFrontOfQueue(m);
1544 }
1545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 private boolean _isProviderEnabledLocked(String provider) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001547 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001549 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001550 if (p == null) {
Mike Lockwoodf4d207b2010-07-17 08:21:33 -04001551 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 }
1553 return isAllowedBySettingsLocked(provider);
1554 }
1555
Nick Pellye0fd6932012-07-11 10:26:13 -07001556 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001557 public Location getLastKnownLocation(String provider) {
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001558 if (LOCAL_LOGV) {
1559 Slog.v(TAG, "getLastKnownLocation: " + provider);
1560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001561 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001562 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 return _getLastKnownLocationLocked(provider);
1564 }
1565 } catch (SecurityException se) {
1566 throw se;
1567 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001568 Slog.e(TAG, "getLastKnownLocation got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 return null;
1570 }
1571 }
1572
1573 private Location _getLastKnownLocationLocked(String provider) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001574 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001576 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 if (p == null) {
Mike Lockwoodf4d207b2010-07-17 08:21:33 -04001578 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001579 }
1580
1581 if (!isAllowedBySettingsLocked(provider)) {
1582 return null;
1583 }
1584
Mike Lockwood9aa1fa22009-09-01 07:51:15 -04001585 return mLastKnownLocation.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 }
1587
1588 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1589 // Always broadcast the first update
1590 if (lastLoc == null) {
1591 return true;
1592 }
1593
Nick Pellyf1be6862012-05-15 10:53:42 -07001594 // Check whether sufficient time has passed
1595 long minTime = record.mMinTime;
Nick Pelly2eeeec22012-07-18 13:13:37 -07001596 long delta = (loc.getElapsedRealtimeNano() - lastLoc.getElapsedRealtimeNano()) / 1000000L;
1597 if (delta < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001598 return false;
1599 }
1600
1601 // Check whether sufficient distance has been traveled
1602 double minDistance = record.mMinDistance;
1603 if (minDistance > 0.0) {
1604 if (loc.distanceTo(lastLoc) <= minDistance) {
1605 return false;
1606 }
1607 }
1608
1609 return true;
1610 }
1611
Mike Lockwooda4903f22010-02-17 06:42:23 -05001612 private void handleLocationChangedLocked(Location location, boolean passive) {
1613 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1615 if (records == null || records.size() == 0) {
1616 return;
1617 }
1618
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001619 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 if (p == null) {
1621 return;
1622 }
1623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001624 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001625 Location lastLocation = mLastKnownLocation.get(provider);
1626 if (lastLocation == null) {
1627 mLastKnownLocation.put(provider, new Location(location));
1628 } else {
1629 lastLocation.set(location);
1630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001631
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 // Fetch latest status update time
1633 long newStatusUpdateTime = p.getStatusUpdateTime();
1634
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001635 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001636 Bundle extras = new Bundle();
1637 int status = p.getStatus(extras);
1638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001639 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641 // Broadcast location or status to all listeners
1642 final int N = records.size();
1643 for (int i=0; i<N; i++) {
1644 UpdateRecord r = records.get(i);
1645 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001646 boolean receiverDead = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001648 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001649 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1650 if (lastLoc == null) {
1651 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001652 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001653 } else {
1654 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001655 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001656 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001657 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001658 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
1660 }
1661
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001662 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001663 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1664 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1665
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001666 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001667 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001668 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001669 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001670 }
1671 }
1672
1673 // remove receiver if it is dead or we just processed a single shot request
1674 if (receiverDead || r.mSingleShot) {
1675 if (deadReceivers == null) {
1676 deadReceivers = new ArrayList<Receiver>();
1677 }
1678 if (!deadReceivers.contains(receiver)) {
1679 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001680 }
1681 }
1682 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001684 if (deadReceivers != null) {
1685 for (int i=deadReceivers.size()-1; i>=0; i--) {
1686 removeUpdatesLocked(deadReceivers.get(i));
1687 }
1688 }
1689 }
1690
1691 private class LocationWorkerHandler extends Handler {
1692
1693 @Override
1694 public void handleMessage(Message msg) {
1695 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001696 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1697 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001699 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001700 Location location = (Location) msg.obj;
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001701 String provider = location.getProvider();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001702 boolean passive = (msg.arg1 == 1);
Mike Lockwood98cb6672009-04-17 18:03:44 -04001703
Mike Lockwooda4903f22010-02-17 06:42:23 -05001704 if (!passive) {
1705 // notify other providers of the new location
1706 for (int i = mProviders.size() - 1; i >= 0; i--) {
1707 LocationProviderInterface p = mProviders.get(i);
1708 if (!provider.equals(p.getName())) {
1709 p.updateLocation(location);
1710 }
Mike Lockwood98cb6672009-04-17 18:03:44 -04001711 }
1712 }
1713
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001714 if (isAllowedBySettingsLocked(provider)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05001715 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001718 } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
1719 String packageName = (String) msg.obj;
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001720
Nick Pelly00355d52012-05-27 16:12:45 -07001721 // reconnect to external providers if there is a better package
1722 if (mNetworkLocationProviderPackageName != null &&
1723 mPackageManager.resolveService(
1724 new Intent(LocationProviderProxy.SERVICE_ACTION)
1725 .setPackage(packageName), 0) != null) {
1726 // package implements service, perform full check
1727 String bestPackage = findBestPackage(
1728 LocationProviderProxy.SERVICE_ACTION,
1729 mNetworkLocationProviderPackageName);
1730 if (packageName.equals(bestPackage)) {
1731 mNetworkLocationProvider.reconnect(bestPackage);
1732 mNetworkLocationProviderPackageName = packageName;
1733 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001734 }
Nick Pelly00355d52012-05-27 16:12:45 -07001735 if (mGeocodeProviderPackageName != null &&
1736 mPackageManager.resolveService(
1737 new Intent(GeocoderProxy.SERVICE_ACTION)
1738 .setPackage(packageName), 0) != null) {
1739 // package implements service, perform full check
1740 String bestPackage = findBestPackage(
1741 GeocoderProxy.SERVICE_ACTION,
1742 mGeocodeProviderPackageName);
1743 if (packageName.equals(bestPackage)) {
1744 mGeocodeProvider.reconnect(bestPackage);
1745 mGeocodeProviderPackageName = packageName;
1746 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001747 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001748 }
1749 } catch (Exception e) {
1750 // Log, don't crash!
Joe Onorato8a9b2202010-02-26 18:56:32 -08001751 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 }
1753 }
1754 }
1755
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001756 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1757 @Override
1758 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 String action = intent.getAction();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001760 boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
1761 if (queryRestart
1762 || action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001763 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001764 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001765 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001766 int uidList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001767 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001768 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1769 } else {
1770 uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
1771 }
1772 if (uidList == null || uidList.length == 0) {
1773 return;
1774 }
1775 for (int uid : uidList) {
1776 if (uid >= 0) {
1777 ArrayList<Receiver> removedRecs = null;
1778 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1779 for (int j=i.size()-1; j>=0; j--) {
1780 UpdateRecord ur = i.get(j);
1781 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001782 if (queryRestart) {
1783 setResultCode(Activity.RESULT_OK);
1784 return;
1785 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001786 if (removedRecs == null) {
1787 removedRecs = new ArrayList<Receiver>();
1788 }
1789 if (!removedRecs.contains(ur.mReceiver)) {
1790 removedRecs.add(ur.mReceiver);
1791 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792 }
1793 }
1794 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001795 }
1796 }
1797 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001798 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 boolean noConnectivity =
1800 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1801 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001802 mNetworkState = LocationProvider.AVAILABLE;
1803 } else {
1804 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001806
1807 final ConnectivityManager connManager = (ConnectivityManager) context
1808 .getSystemService(Context.CONNECTIVITY_SERVICE);
1809 final NetworkInfo info = connManager.getActiveNetworkInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001810
1811 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001812 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001813 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001814 LocationProviderInterface provider = mProviders.get(i);
Mike Lockwoodf19a7852010-05-11 15:35:09 -04001815 if (provider.requiresNetwork()) {
Mike Lockwood03d24672009-10-08 15:45:03 -04001816 provider.updateNetworkState(mNetworkState, info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817 }
1818 }
1819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001820 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001822 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823
Mike Lockwoode97ae402010-09-29 15:23:46 -04001824 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1825 @Override
1826 public void onPackageUpdateFinished(String packageName, int uid) {
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001827 // Called by main thread; divert work to LocationWorker.
1828 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
Mike Lockwoode97ae402010-09-29 15:23:46 -04001829 }
Nick Pelly00355d52012-05-27 16:12:45 -07001830 @Override
1831 public void onPackageAdded(String packageName, int uid) {
1832 // Called by main thread; divert work to LocationWorker.
1833 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
1834 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001835 @Override
1836 public void onPackageDisappeared(String packageName, int uid) {
1837 mGeofenceManager.removeFence(packageName);
1838 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001839 };
1840
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 // Wake locks
1842
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001843 private void incrementPendingBroadcasts() {
1844 synchronized (mWakeLock) {
1845 if (mPendingBroadcasts++ == 0) {
1846 try {
1847 mWakeLock.acquire();
1848 log("Acquired wakelock");
1849 } catch (Exception e) {
1850 // This is to catch a runtime exception thrown when we try to release an
1851 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001852 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001853 }
1854 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001855 }
1856 }
1857
1858 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001859 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001860 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001861 try {
1862 // Release wake lock
1863 if (mWakeLock.isHeld()) {
1864 mWakeLock.release();
1865 log("Released wakelock");
1866 } else {
1867 log("Can't release wakelock again!");
1868 }
1869 } catch (Exception e) {
1870 // This is to catch a runtime exception thrown when we try to release an
1871 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001872 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001873 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001874 }
1875 }
1876 }
1877
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001878 // Geocoder
1879
Nick Pellye0fd6932012-07-11 10:26:13 -07001880 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001881 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001882 return mGeocodeProvider != null;
1883 }
1884
Nick Pellye0fd6932012-07-11 10:26:13 -07001885 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001886 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001887 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001888 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001889 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1890 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001892 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 }
1894
Mike Lockwooda55c3212009-04-15 11:10:11 -04001895
Nick Pellye0fd6932012-07-11 10:26:13 -07001896 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001898 double lowerLeftLatitude, double lowerLeftLongitude,
1899 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001900 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001901
1902 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001903 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1904 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1905 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001907 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001908 }
1909
1910 // Mock Providers
1911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001912 private void checkMockPermissionsSafe() {
1913 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1914 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1915 if (!allowMocks) {
1916 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1917 }
1918
1919 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1920 PackageManager.PERMISSION_GRANTED) {
1921 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001923 }
1924
Nick Pellye0fd6932012-07-11 10:26:13 -07001925 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1927 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1928 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1929 checkMockPermissionsSafe();
1930
Mike Lockwooda4903f22010-02-17 06:42:23 -05001931 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1932 throw new IllegalArgumentException("Cannot mock the passive location provider");
1933 }
1934
Mike Lockwood86328a92009-10-23 08:38:25 -04001935 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001936 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001937 MockProvider provider = new MockProvider(name, this,
1938 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001939 requiresCell, hasMonetaryCost, supportsAltitude,
1940 supportsSpeed, supportsBearing, powerRequirement, accuracy);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001941 // remove the real provider if we are replacing GPS or network provider
1942 if (LocationManager.GPS_PROVIDER.equals(name)
1943 || LocationManager.NETWORK_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001944 LocationProviderInterface p = mProvidersByName.get(name);
1945 if (p != null) {
1946 p.enableLocationTracking(false);
1947 removeProvider(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001948 }
1949 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001950 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001951 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1952 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001953 addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001954 mMockProviders.put(name, provider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001955 mLastKnownLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 updateProvidersLocked();
1957 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001958 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001959 }
1960
Nick Pellye0fd6932012-07-11 10:26:13 -07001961 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001962 public void removeTestProvider(String provider) {
1963 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001964 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001965 MockProvider mockProvider = mMockProviders.get(provider);
1966 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1968 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001969 long identity = Binder.clearCallingIdentity();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001970 removeProvider(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001971 mMockProviders.remove(mockProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001972 // reinstall real provider if we were mocking GPS or network provider
1973 if (LocationManager.GPS_PROVIDER.equals(provider) &&
1974 mGpsLocationProvider != null) {
1975 addProvider(mGpsLocationProvider);
1976 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
1977 mNetworkLocationProvider != null) {
1978 addProvider(mNetworkLocationProvider);
1979 }
1980 mLastKnownLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001982 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 }
1984 }
1985
Nick Pellye0fd6932012-07-11 10:26:13 -07001986 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001987 public void setTestProviderLocation(String provider, Location loc) {
1988 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001989 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001990 MockProvider mockProvider = mMockProviders.get(provider);
1991 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1993 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001994 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1995 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001996 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001997 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
1999 }
2000
Nick Pellye0fd6932012-07-11 10:26:13 -07002001 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 public void clearTestProviderLocation(String provider) {
2003 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002004 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002005 MockProvider mockProvider = mMockProviders.get(provider);
2006 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002007 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2008 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002009 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002010 }
2011 }
2012
Nick Pellye0fd6932012-07-11 10:26:13 -07002013 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002014 public void setTestProviderEnabled(String provider, boolean enabled) {
2015 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002016 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002017 MockProvider mockProvider = mMockProviders.get(provider);
2018 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2020 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002021 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002023 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002024 mEnabledProviders.add(provider);
2025 mDisabledProviders.remove(provider);
2026 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002027 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 mEnabledProviders.remove(provider);
2029 mDisabledProviders.add(provider);
2030 }
2031 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002032 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002033 }
2034 }
2035
Nick Pellye0fd6932012-07-11 10:26:13 -07002036 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 public void clearTestProviderEnabled(String provider) {
2038 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002039 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002040 MockProvider mockProvider = mMockProviders.get(provider);
2041 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002042 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2043 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002044 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 mEnabledProviders.remove(provider);
2046 mDisabledProviders.remove(provider);
2047 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002048 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002049 }
2050 }
2051
Nick Pellye0fd6932012-07-11 10:26:13 -07002052 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2054 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002055 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002056 MockProvider mockProvider = mMockProviders.get(provider);
2057 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002058 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2059 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002060 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002061 }
2062 }
2063
Nick Pellye0fd6932012-07-11 10:26:13 -07002064 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002065 public void clearTestProviderStatus(String provider) {
2066 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002067 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002068 MockProvider mockProvider = mMockProviders.get(provider);
2069 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2071 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002072 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074 }
2075
2076 private void log(String log) {
2077 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002078 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002079 }
2080 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002081
2082 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002083 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2084 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2085 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002086 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 + Binder.getCallingPid()
2088 + ", uid=" + Binder.getCallingUid());
2089 return;
2090 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002091
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002092 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 pw.println("Current Location Manager state:");
2094 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002095 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002096 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002097 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002098 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002099 }
2100 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002101 for (Receiver i : mReceivers.values()) {
2102 pw.println(" " + i + ":");
2103 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 pw.println(" " + j.getKey() + ":");
2105 j.getValue().dump(pw, " ");
2106 }
2107 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002108 pw.println(" Records by Provider:");
2109 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2110 : mRecordsByProvider.entrySet()) {
2111 pw.println(" " + i.getKey() + ":");
2112 for (UpdateRecord j : i.getValue()) {
2113 pw.println(" " + j + ":");
2114 j.dump(pw, " ");
2115 }
2116 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002117 pw.println(" Last Known Locations:");
2118 for (Map.Entry<String, Location> i
2119 : mLastKnownLocation.entrySet()) {
2120 pw.println(" " + i.getKey() + ":");
2121 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2122 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002123 mGeofenceManager.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 if (mEnabledProviders.size() > 0) {
2125 pw.println(" Enabled Providers:");
2126 for (String i : mEnabledProviders) {
2127 pw.println(" " + i);
2128 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002130 }
2131 if (mDisabledProviders.size() > 0) {
2132 pw.println(" Disabled Providers:");
2133 for (String i : mDisabledProviders) {
2134 pw.println(" " + i);
2135 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002136
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002137 }
2138 if (mMockProviders.size() > 0) {
2139 pw.println(" Mock Providers:");
2140 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002141 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002142 }
2143 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002144 for (LocationProviderInterface provider: mProviders) {
2145 String state = provider.getInternalState();
2146 if (state != null) {
2147 pw.println(provider.getName() + " Internal State:");
2148 pw.write(state);
2149 }
2150 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002151 }
2152 }
2153}