blob: 06b056d4abe0b5386ab8b161aeda48e0b9a0d75f [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
Mike Lockwood4e50b782009-04-03 08:24:43 -07001535 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1536 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
Mike Lockwooda4903f22010-02-17 06:42:23 -05001537 m.arg1 = (passive ? 1 : 0);
Mike Lockwood4e50b782009-04-03 08:24:43 -07001538 mLocationHandler.sendMessageAtFrontOfQueue(m);
1539 }
1540
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001541 private boolean _isProviderEnabledLocked(String provider) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001542 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001543
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001544 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001545 if (p == null) {
Mike Lockwoodf4d207b2010-07-17 08:21:33 -04001546 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548 return isAllowedBySettingsLocked(provider);
1549 }
1550
Nick Pellye0fd6932012-07-11 10:26:13 -07001551 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 public Location getLastKnownLocation(String provider) {
Mike Lockwood4a7b65e2010-10-25 16:35:55 -04001553 if (LOCAL_LOGV) {
1554 Slog.v(TAG, "getLastKnownLocation: " + provider);
1555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001557 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001558 return _getLastKnownLocationLocked(provider);
1559 }
1560 } catch (SecurityException se) {
1561 throw se;
1562 } catch (Exception e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001563 Slog.e(TAG, "getLastKnownLocation got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001564 return null;
1565 }
1566 }
1567
1568 private Location _getLastKnownLocationLocked(String provider) {
Dianne Hackborn6c418d52011-06-29 14:05:33 -07001569 checkPermissionsSafe(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001570
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001571 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 if (p == null) {
Mike Lockwoodf4d207b2010-07-17 08:21:33 -04001573 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
1575
1576 if (!isAllowedBySettingsLocked(provider)) {
1577 return null;
1578 }
1579
Mike Lockwood9aa1fa22009-09-01 07:51:15 -04001580 return mLastKnownLocation.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 }
1582
1583 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1584 // Always broadcast the first update
1585 if (lastLoc == null) {
1586 return true;
1587 }
1588
Nick Pellyf1be6862012-05-15 10:53:42 -07001589 // Check whether sufficient time has passed
1590 long minTime = record.mMinTime;
1591 if (loc.getTime() - lastLoc.getTime() < minTime - MAX_PROVIDER_SCHEDULING_JITTER) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001592 return false;
1593 }
1594
1595 // Check whether sufficient distance has been traveled
1596 double minDistance = record.mMinDistance;
1597 if (minDistance > 0.0) {
1598 if (loc.distanceTo(lastLoc) <= minDistance) {
1599 return false;
1600 }
1601 }
1602
1603 return true;
1604 }
1605
Mike Lockwooda4903f22010-02-17 06:42:23 -05001606 private void handleLocationChangedLocked(Location location, boolean passive) {
1607 String provider = (passive ? LocationManager.PASSIVE_PROVIDER : location.getProvider());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1609 if (records == null || records.size() == 0) {
1610 return;
1611 }
1612
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001613 LocationProviderInterface p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 if (p == null) {
1615 return;
1616 }
1617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001618 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001619 Location lastLocation = mLastKnownLocation.get(provider);
1620 if (lastLocation == null) {
1621 mLastKnownLocation.put(provider, new Location(location));
1622 } else {
1623 lastLocation.set(location);
1624 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001625
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001626 // Fetch latest status update time
1627 long newStatusUpdateTime = p.getStatusUpdateTime();
1628
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001629 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001630 Bundle extras = new Bundle();
1631 int status = p.getStatus(extras);
1632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001633 ArrayList<Receiver> deadReceivers = null;
Nick Pellye0fd6932012-07-11 10:26:13 -07001634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001635 // Broadcast location or status to all listeners
1636 final int N = records.size();
1637 for (int i=0; i<N; i++) {
1638 UpdateRecord r = records.get(i);
1639 Receiver receiver = r.mReceiver;
Mike Lockwood03ca2162010-04-01 08:10:09 -07001640 boolean receiverDead = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001641
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001642 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001643 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1644 if (lastLoc == null) {
1645 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001646 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001647 } else {
1648 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001649 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001650 if (!receiver.callLocationChangedLocked(location)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08001651 Slog.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001652 receiverDead = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 }
1654 }
1655
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001656 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001657 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1658 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1659
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001660 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
Mike Lockwood03ca2162010-04-01 08:10:09 -07001662 receiverDead = true;
Joe Onorato8a9b2202010-02-26 18:56:32 -08001663 Slog.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
Mike Lockwood03ca2162010-04-01 08:10:09 -07001664 }
1665 }
1666
1667 // remove receiver if it is dead or we just processed a single shot request
1668 if (receiverDead || r.mSingleShot) {
1669 if (deadReceivers == null) {
1670 deadReceivers = new ArrayList<Receiver>();
1671 }
1672 if (!deadReceivers.contains(receiver)) {
1673 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001674 }
1675 }
1676 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001678 if (deadReceivers != null) {
1679 for (int i=deadReceivers.size()-1; i>=0; i--) {
1680 removeUpdatesLocked(deadReceivers.get(i));
1681 }
1682 }
1683 }
1684
1685 private class LocationWorkerHandler extends Handler {
1686
1687 @Override
1688 public void handleMessage(Message msg) {
1689 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001690 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1691 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001692
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001693 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001694 Location location = (Location) msg.obj;
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001695 String provider = location.getProvider();
Mike Lockwooda4903f22010-02-17 06:42:23 -05001696 boolean passive = (msg.arg1 == 1);
Mike Lockwood98cb6672009-04-17 18:03:44 -04001697
Mike Lockwooda4903f22010-02-17 06:42:23 -05001698 if (!passive) {
1699 // notify other providers of the new location
1700 for (int i = mProviders.size() - 1; i >= 0; i--) {
1701 LocationProviderInterface p = mProviders.get(i);
1702 if (!provider.equals(p.getName())) {
1703 p.updateLocation(location);
1704 }
Mike Lockwood98cb6672009-04-17 18:03:44 -04001705 }
1706 }
1707
Mike Lockwoodfd6e5f02009-05-21 11:28:20 -04001708 if (isAllowedBySettingsLocked(provider)) {
Mike Lockwooda4903f22010-02-17 06:42:23 -05001709 handleLocationChangedLocked(location, passive);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001710 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001711 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001712 } else if (msg.what == MESSAGE_PACKAGE_UPDATED) {
1713 String packageName = (String) msg.obj;
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001714
Nick Pelly00355d52012-05-27 16:12:45 -07001715 // reconnect to external providers if there is a better package
1716 if (mNetworkLocationProviderPackageName != null &&
1717 mPackageManager.resolveService(
1718 new Intent(LocationProviderProxy.SERVICE_ACTION)
1719 .setPackage(packageName), 0) != null) {
1720 // package implements service, perform full check
1721 String bestPackage = findBestPackage(
1722 LocationProviderProxy.SERVICE_ACTION,
1723 mNetworkLocationProviderPackageName);
1724 if (packageName.equals(bestPackage)) {
1725 mNetworkLocationProvider.reconnect(bestPackage);
1726 mNetworkLocationProviderPackageName = packageName;
1727 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001728 }
Nick Pelly00355d52012-05-27 16:12:45 -07001729 if (mGeocodeProviderPackageName != null &&
1730 mPackageManager.resolveService(
1731 new Intent(GeocoderProxy.SERVICE_ACTION)
1732 .setPackage(packageName), 0) != null) {
1733 // package implements service, perform full check
1734 String bestPackage = findBestPackage(
1735 GeocoderProxy.SERVICE_ACTION,
1736 mGeocodeProviderPackageName);
1737 if (packageName.equals(bestPackage)) {
1738 mGeocodeProvider.reconnect(bestPackage);
1739 mGeocodeProviderPackageName = packageName;
1740 }
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001742 }
1743 } catch (Exception e) {
1744 // Log, don't crash!
Joe Onorato8a9b2202010-02-26 18:56:32 -08001745 Slog.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 }
1747 }
1748 }
1749
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001750 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
1751 @Override
1752 public void onReceive(Context context, Intent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 String action = intent.getAction();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001754 boolean queryRestart = action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART);
1755 if (queryRestart
1756 || action.equals(Intent.ACTION_PACKAGE_REMOVED)
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001757 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001758 || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001759 synchronized (mLock) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001760 int uidList[] = null;
Suchi Amalapurapub56ae202010-02-04 22:51:07 -08001761 if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001762 uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST);
1763 } else {
1764 uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)};
1765 }
1766 if (uidList == null || uidList.length == 0) {
1767 return;
1768 }
1769 for (int uid : uidList) {
1770 if (uid >= 0) {
1771 ArrayList<Receiver> removedRecs = null;
1772 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1773 for (int j=i.size()-1; j>=0; j--) {
1774 UpdateRecord ur = i.get(j);
1775 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001776 if (queryRestart) {
1777 setResultCode(Activity.RESULT_OK);
1778 return;
1779 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001780 if (removedRecs == null) {
1781 removedRecs = new ArrayList<Receiver>();
1782 }
1783 if (!removedRecs.contains(ur.mReceiver)) {
1784 removedRecs.add(ur.mReceiver);
1785 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 }
1787 }
1788 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 }
1790 }
1791 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001792 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 boolean noConnectivity =
1794 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1795 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001796 mNetworkState = LocationProvider.AVAILABLE;
1797 } else {
1798 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001799 }
Jeff Sharkey5e613312012-01-30 11:16:20 -08001800
1801 final ConnectivityManager connManager = (ConnectivityManager) context
1802 .getSystemService(Context.CONNECTIVITY_SERVICE);
1803 final NetworkInfo info = connManager.getActiveNetworkInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804
1805 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001806 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001807 for (int i = mProviders.size() - 1; i >= 0; i--) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001808 LocationProviderInterface provider = mProviders.get(i);
Mike Lockwoodf19a7852010-05-11 15:35:09 -04001809 if (provider.requiresNetwork()) {
Mike Lockwood03d24672009-10-08 15:45:03 -04001810 provider.updateNetworkState(mNetworkState, info);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001811 }
1812 }
1813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001815 }
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001816 };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001817
Mike Lockwoode97ae402010-09-29 15:23:46 -04001818 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
1819 @Override
1820 public void onPackageUpdateFinished(String packageName, int uid) {
Mark Vandevoorde8863c432010-10-04 14:23:24 -07001821 // Called by main thread; divert work to LocationWorker.
1822 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
Mike Lockwoode97ae402010-09-29 15:23:46 -04001823 }
Nick Pelly00355d52012-05-27 16:12:45 -07001824 @Override
1825 public void onPackageAdded(String packageName, int uid) {
1826 // Called by main thread; divert work to LocationWorker.
1827 Message.obtain(mLocationHandler, MESSAGE_PACKAGE_UPDATED, packageName).sendToTarget();
1828 }
Nick Pellye0fd6932012-07-11 10:26:13 -07001829 @Override
1830 public void onPackageDisappeared(String packageName, int uid) {
1831 mGeofenceManager.removeFence(packageName);
1832 }
Mike Lockwoode97ae402010-09-29 15:23:46 -04001833 };
1834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001835 // Wake locks
1836
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001837 private void incrementPendingBroadcasts() {
1838 synchronized (mWakeLock) {
1839 if (mPendingBroadcasts++ == 0) {
1840 try {
1841 mWakeLock.acquire();
1842 log("Acquired wakelock");
1843 } catch (Exception e) {
1844 // This is to catch a runtime exception thrown when we try to release an
1845 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001846 Slog.e(TAG, "exception in acquireWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001847 }
1848 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001849 }
1850 }
1851
1852 private void decrementPendingBroadcasts() {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001853 synchronized (mWakeLock) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001854 if (--mPendingBroadcasts == 0) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001855 try {
1856 // Release wake lock
1857 if (mWakeLock.isHeld()) {
1858 mWakeLock.release();
1859 log("Released wakelock");
1860 } else {
1861 log("Can't release wakelock again!");
1862 }
1863 } catch (Exception e) {
1864 // This is to catch a runtime exception thrown when we try to release an
1865 // already released lock.
Joe Onorato8a9b2202010-02-26 18:56:32 -08001866 Slog.e(TAG, "exception in releaseWakeLock()", e);
Mike Lockwood0528b9b2009-05-07 10:12:54 -04001867 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001868 }
1869 }
1870 }
1871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001872 // Geocoder
1873
Nick Pellye0fd6932012-07-11 10:26:13 -07001874 @Override
Mike Lockwoode15735a2010-09-20 17:48:47 -04001875 public boolean geocoderIsPresent() {
Mark Vandevoorde01ac80b2010-05-21 15:43:26 -07001876 return mGeocodeProvider != null;
1877 }
1878
Nick Pellye0fd6932012-07-11 10:26:13 -07001879 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001880 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001881 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001882 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001883 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults,
1884 params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001886 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001887 }
1888
Mike Lockwooda55c3212009-04-15 11:10:11 -04001889
Nick Pellye0fd6932012-07-11 10:26:13 -07001890 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001891 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001892 double lowerLeftLatitude, double lowerLeftLongitude,
1893 double upperRightLatitude, double upperRightLongitude, int maxResults,
Mike Lockwood34901402010-01-04 12:14:21 -05001894 GeocoderParams params, List<Address> addrs) {
Mike Lockwooda55c3212009-04-15 11:10:11 -04001895
1896 if (mGeocodeProvider != null) {
Mike Lockwood628fd6d2010-01-25 22:46:13 -05001897 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1898 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1899 maxResults, params, addrs);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001901 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001902 }
1903
1904 // Mock Providers
1905
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 private void checkMockPermissionsSafe() {
1907 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1908 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1909 if (!allowMocks) {
1910 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1911 }
1912
1913 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1914 PackageManager.PERMISSION_GRANTED) {
1915 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
Nick Pellye0fd6932012-07-11 10:26:13 -07001916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001917 }
1918
Nick Pellye0fd6932012-07-11 10:26:13 -07001919 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1921 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1922 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1923 checkMockPermissionsSafe();
1924
Mike Lockwooda4903f22010-02-17 06:42:23 -05001925 if (LocationManager.PASSIVE_PROVIDER.equals(name)) {
1926 throw new IllegalArgumentException("Cannot mock the passive location provider");
1927 }
1928
Mike Lockwood86328a92009-10-23 08:38:25 -04001929 long identity = Binder.clearCallingIdentity();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001930 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001931 MockProvider provider = new MockProvider(name, this,
1932 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001933 requiresCell, hasMonetaryCost, supportsAltitude,
1934 supportsSpeed, supportsBearing, powerRequirement, accuracy);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001935 // remove the real provider if we are replacing GPS or network provider
1936 if (LocationManager.GPS_PROVIDER.equals(name)
1937 || LocationManager.NETWORK_PROVIDER.equals(name)) {
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001938 LocationProviderInterface p = mProvidersByName.get(name);
1939 if (p != null) {
1940 p.enableLocationTracking(false);
1941 removeProvider(p);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001942 }
1943 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001944 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001945 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1946 }
Mike Lockwoodd03ff942010-02-09 08:46:14 -05001947 addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001948 mMockProviders.put(name, provider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001949 mLastKnownLocation.put(name, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 updateProvidersLocked();
1951 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001952 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 }
1954
Nick Pellye0fd6932012-07-11 10:26:13 -07001955 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001956 public void removeTestProvider(String provider) {
1957 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001958 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001959 MockProvider mockProvider = mMockProviders.get(provider);
1960 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1962 }
Mike Lockwood86328a92009-10-23 08:38:25 -04001963 long identity = Binder.clearCallingIdentity();
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001964 removeProvider(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001965 mMockProviders.remove(mockProvider);
Mike Lockwood7566c1d2009-08-25 10:05:18 -07001966 // reinstall real provider if we were mocking GPS or network provider
1967 if (LocationManager.GPS_PROVIDER.equals(provider) &&
1968 mGpsLocationProvider != null) {
1969 addProvider(mGpsLocationProvider);
1970 } else if (LocationManager.NETWORK_PROVIDER.equals(provider) &&
1971 mNetworkLocationProvider != null) {
1972 addProvider(mNetworkLocationProvider);
1973 }
1974 mLastKnownLocation.put(provider, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001975 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04001976 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 }
1978 }
1979
Nick Pellye0fd6932012-07-11 10:26:13 -07001980 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 public void setTestProviderLocation(String provider, Location loc) {
1982 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001983 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001984 MockProvider mockProvider = mMockProviders.get(provider);
1985 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001986 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1987 }
Mike Lockwood95427cd2009-05-07 13:27:54 -04001988 // clear calling identity so INSTALL_LOCATION_PROVIDER permission is not required
1989 long identity = Binder.clearCallingIdentity();
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001990 mockProvider.setLocation(loc);
Mike Lockwood95427cd2009-05-07 13:27:54 -04001991 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001992 }
1993 }
1994
Nick Pellye0fd6932012-07-11 10:26:13 -07001995 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001996 public void clearTestProviderLocation(String provider) {
1997 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001998 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001999 MockProvider mockProvider = mMockProviders.get(provider);
2000 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002001 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2002 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002003 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002004 }
2005 }
2006
Nick Pellye0fd6932012-07-11 10:26:13 -07002007 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002008 public void setTestProviderEnabled(String provider, boolean enabled) {
2009 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002010 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002011 MockProvider mockProvider = mMockProviders.get(provider);
2012 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002013 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2014 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002015 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002016 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002017 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002018 mEnabledProviders.add(provider);
2019 mDisabledProviders.remove(provider);
2020 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002021 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002022 mEnabledProviders.remove(provider);
2023 mDisabledProviders.add(provider);
2024 }
2025 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002026 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002027 }
2028 }
2029
Nick Pellye0fd6932012-07-11 10:26:13 -07002030 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002031 public void clearTestProviderEnabled(String provider) {
2032 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002033 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002034 MockProvider mockProvider = mMockProviders.get(provider);
2035 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002036 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2037 }
Mike Lockwood86328a92009-10-23 08:38:25 -04002038 long identity = Binder.clearCallingIdentity();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 mEnabledProviders.remove(provider);
2040 mDisabledProviders.remove(provider);
2041 updateProvidersLocked();
Mike Lockwood86328a92009-10-23 08:38:25 -04002042 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 }
2044 }
2045
Nick Pellye0fd6932012-07-11 10:26:13 -07002046 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002047 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2048 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002049 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002050 MockProvider mockProvider = mMockProviders.get(provider);
2051 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2053 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002054 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 }
2056 }
2057
Nick Pellye0fd6932012-07-11 10:26:13 -07002058 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002059 public void clearTestProviderStatus(String provider) {
2060 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002061 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002062 MockProvider mockProvider = mMockProviders.get(provider);
2063 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002064 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2065 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002066 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 }
2068 }
2069
2070 private void log(String log) {
2071 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Joe Onorato8a9b2202010-02-26 18:56:32 -08002072 Slog.d(TAG, log);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 }
2074 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002075
2076 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002077 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2078 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2079 != PackageManager.PERMISSION_GRANTED) {
Mike Lockwood0528b9b2009-05-07 10:12:54 -04002080 pw.println("Permission Denial: can't dump LocationManagerService from from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002081 + Binder.getCallingPid()
2082 + ", uid=" + Binder.getCallingUid());
2083 return;
2084 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002085
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002086 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002087 pw.println("Current Location Manager state:");
2088 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002090 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002091 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002092 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002093 }
2094 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002095 for (Receiver i : mReceivers.values()) {
2096 pw.println(" " + i + ":");
2097 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 pw.println(" " + j.getKey() + ":");
2099 j.getValue().dump(pw, " ");
2100 }
2101 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002102 pw.println(" Records by Provider:");
2103 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2104 : mRecordsByProvider.entrySet()) {
2105 pw.println(" " + i.getKey() + ":");
2106 for (UpdateRecord j : i.getValue()) {
2107 pw.println(" " + j + ":");
2108 j.dump(pw, " ");
2109 }
2110 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002111 pw.println(" Last Known Locations:");
2112 for (Map.Entry<String, Location> i
2113 : mLastKnownLocation.entrySet()) {
2114 pw.println(" " + i.getKey() + ":");
2115 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2116 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002117 mGeofenceManager.dump(pw);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 if (mEnabledProviders.size() > 0) {
2119 pw.println(" Enabled Providers:");
2120 for (String i : mEnabledProviders) {
2121 pw.println(" " + i);
2122 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002124 }
2125 if (mDisabledProviders.size() > 0) {
2126 pw.println(" Disabled Providers:");
2127 for (String i : mDisabledProviders) {
2128 pw.println(" " + i);
2129 }
Nick Pellye0fd6932012-07-11 10:26:13 -07002130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002131 }
2132 if (mMockProviders.size() > 0) {
2133 pw.println(" Mock Providers:");
2134 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002135 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002136 }
2137 }
Fred Fettinger3c8fbdf2010-01-04 15:38:13 -06002138 for (LocationProviderInterface provider: mProviders) {
2139 String state = provider.getInternalState();
2140 if (state != null) {
2141 pw.println(provider.getName() + " Internal State:");
2142 pw.write(state);
2143 }
2144 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 }
2146 }
2147}