blob: d44abaaac472bfeebb8308e17c33adc26caae1e4 [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
19import java.io.BufferedReader;
20import java.io.File;
21import java.io.FileDescriptor;
22import java.io.FileReader;
23import java.io.FileWriter;
24import java.io.IOException;
25import java.io.PrintWriter;
26import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.List;
30import java.util.Map;
Mike Lockwood9637d472009-04-02 21:41:57 -070031import java.util.Observable;
32import java.util.Observer;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import java.util.Set;
34import java.util.regex.Pattern;
35
36import android.app.AlarmManager;
37import android.app.PendingIntent;
38import android.content.BroadcastReceiver;
Mike Lockwood9637d472009-04-02 21:41:57 -070039import android.content.ContentQueryMap;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.ContentResolver;
41import android.content.Context;
42import android.content.Intent;
43import android.content.IntentFilter;
44import android.content.pm.PackageManager;
Mike Lockwood9637d472009-04-02 21:41:57 -070045import android.database.Cursor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.location.Address;
Mike Lockwooda55c3212009-04-15 11:10:11 -040047import android.location.IGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.location.IGpsStatusListener;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -040049import android.location.IGpsStatusProvider;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070050import android.location.ILocationCollector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.location.ILocationListener;
52import android.location.ILocationManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070053import android.location.ILocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.location.Location;
55import android.location.LocationManager;
56import android.location.LocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.net.ConnectivityManager;
58import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.os.Binder;
60import android.os.Bundle;
61import android.os.Handler;
62import android.os.IBinder;
Mike Lockwood3d12b512009-04-21 23:25:35 -070063import android.os.Looper;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.os.Message;
65import android.os.PowerManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070066import android.os.Process;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.os.RemoteException;
68import android.os.SystemClock;
69import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.util.Config;
71import android.util.Log;
72import android.util.PrintWriterPrinter;
73import android.util.SparseIntArray;
74
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import com.android.internal.location.GpsLocationProvider;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070076import com.android.internal.location.LocationProviderProxy;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070077import com.android.internal.location.MockProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import com.android.server.am.BatteryStatsService;
79
80/**
81 * The service class that manages LocationProviders and issues location
82 * updates and alerts.
83 *
84 * {@hide}
85 */
Mike Lockwood3d12b512009-04-21 23:25:35 -070086public class LocationManagerService extends ILocationManager.Stub implements Runnable {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = "LocationManagerService";
The Android Open Source Project10592532009-03-18 17:39:46 -070088 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089
90 // Minimum time interval between last known location writes, in milliseconds.
91 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L;
92
93 // Max time to hold wake lock for, in milliseconds.
94 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
95
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 // The last time a location was written, by provider name.
97 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
98
99 private static final Pattern PATTERN_COMMA = Pattern.compile(",");
100
101 private static final String ACCESS_FINE_LOCATION =
102 android.Manifest.permission.ACCESS_FINE_LOCATION;
103 private static final String ACCESS_COARSE_LOCATION =
104 android.Manifest.permission.ACCESS_COARSE_LOCATION;
105 private static final String ACCESS_MOCK_LOCATION =
106 android.Manifest.permission.ACCESS_MOCK_LOCATION;
107 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
108 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
109
110 // 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;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400122 private LocationProviderProxy mGpsLocationProvider;
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700123 private LocationProviderProxy mNetworkLocationProvider;
Mike Lockwooda55c3212009-04-15 11:10:11 -0400124 private IGeocodeProvider mGeocodeProvider;
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400125 private IGpsStatusProvider mGpsStatusProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 private LocationWorkerHandler mLocationHandler;
127
128 // Handler messages
Mike Lockwood4e50b782009-04-03 08:24:43 -0700129 private static final int MESSAGE_LOCATION_CHANGED = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800130
131 // Alarm manager and wakelock variables
132 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
133 private final static String WAKELOCK_KEY = "LocationManagerService";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private AlarmManager mAlarmManager;
135 private long mAlarmInterval = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 private PowerManager.WakeLock mWakeLock = null;
Mike Lockwood48f17512009-04-23 09:12:08 -0700137 private int mPendingBroadcasts;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 private long mWakeLockAcquireTime = 0;
139 private boolean mWakeLockGpsReceived = true;
140 private boolean mWakeLockNetworkReceived = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400143 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400145 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400147
148 /**
149 * List of location providers.
150 */
151 private final ArrayList<LocationProviderProxy> mProviders =
152 new ArrayList<LocationProviderProxy>();
153 private final HashMap<String, LocationProviderProxy> mProvidersByName
154 = new HashMap<String, LocationProviderProxy>();
155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400157 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400159 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160
161 /**
162 * Mapping from provider name to all its UpdateRecords
163 */
164 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
165 new HashMap<String,ArrayList<UpdateRecord>>();
166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 // Proximity listeners
Mike Lockwood48f17512009-04-23 09:12:08 -0700168 private Receiver mProximityReceiver = null;
169 private ILocationListener mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
171 new HashMap<PendingIntent,ProximityAlert>();
172 private HashSet<ProximityAlert> mProximitiesEntered =
173 new HashSet<ProximityAlert>();
174
175 // Last known location for each provider
176 private HashMap<String,Location> mLastKnownLocation =
177 new HashMap<String,Location>();
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 // Location collector
180 private ILocationCollector mCollector;
181
The Android Open Source Project4df24232009-03-05 14:34:35 -0800182 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800183
Mike Lockwood9637d472009-04-02 21:41:57 -0700184 // for Settings change notification
185 private ContentQueryMap mSettings;
186
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 /**
188 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
189 * location updates.
190 */
Mike Lockwood48f17512009-04-23 09:12:08 -0700191 private final class Receiver implements IBinder.DeathRecipient, PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800192 final ILocationListener mListener;
193 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 final Object mKey;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400195 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
Mike Lockwood48f17512009-04-23 09:12:08 -0700196 int mPendingBroadcasts;
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 }
223
224
225 @Override
226 public String toString() {
227 if (mListener != null) {
228 return "Receiver{"
229 + 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 {
232 return "Receiver{"
233 + 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 }
236 }
237
238 public boolean isListener() {
239 return mListener != null;
240 }
241
242 public boolean isPendingIntent() {
243 return mPendingIntent != null;
244 }
245
246 public ILocationListener getListener() {
247 if (mListener != null) {
248 return mListener;
249 }
250 throw new IllegalStateException("Request for non-existent listener");
251 }
252
253 public PendingIntent getPendingIntent() {
254 if (mPendingIntent != null) {
255 return mPendingIntent;
256 }
257 throw new IllegalStateException("Request for non-existent intent");
258 }
259
260 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
261 if (mListener != null) {
262 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700263 synchronized (this) {
264 // synchronize to ensure incrementPendingBroadcastsLocked()
265 // is called before decrementPendingBroadcasts()
266 mListener.onStatusChanged(provider, status, extras);
267 if (mListener != mProximityListener) {
268 // call this after broadcasting so we do not increment
269 // if we throw an exeption.
270 incrementPendingBroadcastsLocked();
271 }
272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800273 } catch (RemoteException e) {
274 return false;
275 }
276 } else {
277 Intent statusChanged = new Intent();
278 statusChanged.putExtras(extras);
279 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
280 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700281 synchronized (this) {
282 // synchronize to ensure incrementPendingBroadcastsLocked()
283 // is called before decrementPendingBroadcasts()
284 mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler);
285 // call this after broadcasting so we do not increment
286 // if we throw an exeption.
287 incrementPendingBroadcastsLocked();
288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289 } catch (PendingIntent.CanceledException e) {
290 return false;
291 }
292 }
293 return true;
294 }
295
296 public boolean callLocationChangedLocked(Location location) {
297 if (mListener != null) {
298 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700299 synchronized (this) {
300 // synchronize to ensure incrementPendingBroadcastsLocked()
301 // is called before decrementPendingBroadcasts()
302 mListener.onLocationChanged(location);
303 if (mListener != mProximityListener) {
304 // call this after broadcasting so we do not increment
305 // if we throw an exeption.
306 incrementPendingBroadcastsLocked();
307 }
308 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 } catch (RemoteException e) {
310 return false;
311 }
312 } else {
313 Intent locationChanged = new Intent();
314 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
315 try {
Mike Lockwood48f17512009-04-23 09:12:08 -0700316 synchronized (this) {
317 // synchronize to ensure incrementPendingBroadcastsLocked()
318 // is called before decrementPendingBroadcasts()
319 mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler);
320 // call this after broadcasting so we do not increment
321 // if we throw an exeption.
322 incrementPendingBroadcastsLocked();
323 }
324 } catch (PendingIntent.CanceledException e) {
325 return false;
326 }
327 }
328 return true;
329 }
330
331 public boolean callProviderEnabledLocked(String provider, boolean enabled) {
332 if (mListener != null) {
333 try {
334 synchronized (this) {
335 // synchronize to ensure incrementPendingBroadcastsLocked()
336 // is called before decrementPendingBroadcasts()
337 if (enabled) {
338 mListener.onProviderEnabled(provider);
339 } else {
340 mListener.onProviderDisabled(provider);
341 }
342 if (mListener != mProximityListener) {
343 // call this after broadcasting so we do not increment
344 // if we throw an exeption.
345 incrementPendingBroadcastsLocked();
346 }
347 }
348 } catch (RemoteException e) {
349 return false;
350 }
351 } else {
352 Intent providerIntent = new Intent();
353 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
354 try {
355 synchronized (this) {
356 // synchronize to ensure incrementPendingBroadcastsLocked()
357 // is called before decrementPendingBroadcasts()
358 mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler);
359 // call this after broadcasting so we do not increment
360 // if we throw an exeption.
361 incrementPendingBroadcastsLocked();
362 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 } catch (PendingIntent.CanceledException e) {
364 return false;
365 }
366 }
367 return true;
368 }
369
370 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700371 if (LOCAL_LOGV) {
372 Log.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400374 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800375 removeUpdatesLocked(this);
376 }
Mike Lockwood48f17512009-04-23 09:12:08 -0700377 synchronized (this) {
378 if (mPendingBroadcasts > 0) {
379 LocationManagerService.this.decrementPendingBroadcasts();
380 mPendingBroadcasts = 0;
381 }
382 }
383 }
384
385 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
386 int resultCode, String resultData, Bundle resultExtras) {
387 decrementPendingBroadcasts();
388 }
389
390 // this must be called while synchronized by callerin a synchronized block
391 // containing the sending of the broadcaset
392 private void incrementPendingBroadcastsLocked() {
393 if (mPendingBroadcasts++ == 0) {
394 synchronized (mLock) {
395 LocationManagerService.this.incrementPendingBroadcastsLocked();
396 }
397 }
398 }
399
400 private void decrementPendingBroadcasts() {
401 synchronized (this) {
402 if (--mPendingBroadcasts == 0) {
403 LocationManagerService.this.decrementPendingBroadcasts();
404 }
405 }
406 }
407 }
408
409 public void locationCallbackFinished(ILocationListener listener) {
410 Receiver receiver = getReceiver(listener);
411 if (receiver != null) {
412 receiver.decrementPendingBroadcasts();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 }
414 }
415
Mike Lockwood9637d472009-04-02 21:41:57 -0700416 private final class SettingsObserver implements Observer {
417 public void update(Observable o, Object arg) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400418 synchronized (mLock) {
Mike Lockwood9637d472009-04-02 21:41:57 -0700419 updateProvidersLocked();
420 }
421 }
422 }
423
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800424 private Location readLastKnownLocationLocked(String provider) {
425 Location location = null;
426 String s = null;
427 try {
428 File f = new File(LocationManager.SYSTEM_DIR + "/location."
429 + provider);
430 if (!f.exists()) {
431 return null;
432 }
433 BufferedReader reader = new BufferedReader(new FileReader(f), 256);
434 s = reader.readLine();
435 } catch (IOException e) {
436 Log.w(TAG, "Unable to read last known location", e);
437 }
438
439 if (s == null) {
440 return null;
441 }
442 try {
443 String[] tokens = PATTERN_COMMA.split(s);
444 int idx = 0;
445 long time = Long.parseLong(tokens[idx++]);
446 double latitude = Double.parseDouble(tokens[idx++]);
447 double longitude = Double.parseDouble(tokens[idx++]);
448 double altitude = Double.parseDouble(tokens[idx++]);
449 float bearing = Float.parseFloat(tokens[idx++]);
450 float speed = Float.parseFloat(tokens[idx++]);
451
452 location = new Location(provider);
453 location.setTime(time);
454 location.setLatitude(latitude);
455 location.setLongitude(longitude);
456 location.setAltitude(altitude);
457 location.setBearing(bearing);
458 location.setSpeed(speed);
459 } catch (NumberFormatException nfe) {
460 Log.e(TAG, "NumberFormatException reading last known location", nfe);
461 return null;
462 }
463
464 return location;
465 }
466
467 private void writeLastKnownLocationLocked(String provider,
468 Location location) {
469 long now = SystemClock.elapsedRealtime();
470 Long last = mLastWriteTime.get(provider);
471 if ((last != null)
472 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
473 return;
474 }
475 mLastWriteTime.put(provider, now);
476
477 StringBuilder sb = new StringBuilder(100);
478 sb.append(location.getTime());
479 sb.append(',');
480 sb.append(location.getLatitude());
481 sb.append(',');
482 sb.append(location.getLongitude());
483 sb.append(',');
484 sb.append(location.getAltitude());
485 sb.append(',');
486 sb.append(location.getBearing());
487 sb.append(',');
488 sb.append(location.getSpeed());
489
490 FileWriter writer = null;
491 try {
492 File d = new File(LocationManager.SYSTEM_DIR);
493 if (!d.exists()) {
494 if (!d.mkdirs()) {
495 Log.w(TAG, "Unable to create directory to write location");
496 return;
497 }
498 }
499 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
500 writer = new FileWriter(f);
501 writer.write(sb.toString());
502 } catch (IOException e) {
503 Log.w(TAG, "Unable to write location", e);
504 } finally {
505 if (writer != null) {
506 try {
507 writer.close();
508 } catch (IOException e) {
509 Log.w(TAG, "Exception closing file", e);
510 }
511 }
512 }
513 }
514
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400515 private void addProvider(LocationProviderProxy provider) {
516 mProviders.add(provider);
517 mProvidersByName.put(provider.getName(), provider);
518 }
519
520 private void removeProvider(LocationProviderProxy provider) {
521 mProviders.remove(provider);
522 mProvidersByName.remove(provider.getName());
523 }
524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 /**
526 * Load providers from /data/location/<provider_name>/
527 * class
528 * kml
529 * nmea
530 * track
531 * location
532 * properties
533 */
534 private void loadProviders() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400535 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 if (sProvidersLoaded) {
537 return;
538 }
539
540 // Load providers
541 loadProvidersLocked();
542 sProvidersLoaded = true;
543 }
544 }
545
546 private void loadProvidersLocked() {
547 try {
548 _loadProvidersLocked();
549 } catch (Exception e) {
550 Log.e(TAG, "Exception loading providers:", e);
551 }
552 }
553
554 private void _loadProvidersLocked() {
555 // Attempt to load "real" providers first
556 if (GpsLocationProvider.isSupported()) {
557 // Create a gps location provider
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400558 GpsLocationProvider provider = new GpsLocationProvider(mContext, this);
559 mGpsStatusProvider = provider.getGpsStatusProvider();
560 mGpsLocationProvider =
561 new LocationProviderProxy(LocationManager.GPS_PROVIDER, provider);
562 addProvider(mGpsLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 }
564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 updateProvidersLocked();
566 }
567
568 /**
569 * @param context the context that the LocationManagerService runs in
570 */
571 public LocationManagerService(Context context) {
572 super();
573 mContext = context;
Mike Lockwood3d12b512009-04-21 23:25:35 -0700574
575 Thread thread = new Thread(null, this, "LocationManagerService");
576 thread.start();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577
The Android Open Source Project10592532009-03-18 17:39:46 -0700578 if (LOCAL_LOGV) {
579 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800580 }
Mike Lockwood3d12b512009-04-21 23:25:35 -0700581 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800582
Mike Lockwood3d12b512009-04-21 23:25:35 -0700583 private void initialize() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 // Alarm manager, needs to be done before calling loadProviders() below
Mike Lockwood3d12b512009-04-21 23:25:35 -0700585 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586
587 // Create a wake lock, needs to be done before calling loadProviders() below
588 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
589 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800591 // Load providers
592 loadProviders();
593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 // Register for Network (Wifi or Mobile) updates
595 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
596 IntentFilter networkIntentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800597 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
598 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700599 mContext.registerReceiver(networkReceiver, networkIntentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600
601 // Register for power updates
602 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
603 IntentFilter intentFilter = new IntentFilter();
604 intentFilter.addAction(ALARM_INTENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
606 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
Mike Lockwood3d12b512009-04-21 23:25:35 -0700607 mContext.registerReceiver(powerStateReceiver, intentFilter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608
Mike Lockwood9637d472009-04-02 21:41:57 -0700609 // listen for settings changes
610 ContentResolver resolver = mContext.getContentResolver();
611 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
612 "(" + Settings.System.NAME + "=?)",
613 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
614 null);
615 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
616 SettingsObserver settingsObserver = new SettingsObserver();
617 mSettings.addObserver(settingsObserver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800618 }
619
Mike Lockwood3d12b512009-04-21 23:25:35 -0700620 public void run()
621 {
622 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
623 Looper.prepare();
624 mLocationHandler = new LocationWorkerHandler();
625 initialize();
626 Looper.loop();
627 }
628
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700629 public void setNetworkLocationProvider(ILocationProvider provider) {
630 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
631 throw new SecurityException(
632 "Installing location providers outside of the system is not supported");
633 }
634
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400635 synchronized (mLock) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700636 mNetworkLocationProvider =
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400637 new LocationProviderProxy(LocationManager.NETWORK_PROVIDER, provider);
638 addProvider(mNetworkLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 updateProvidersLocked();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800640
641 // notify NetworkLocationProvider of any events it might have missed
Mike Lockwoodf113fbe2009-04-06 05:17:28 -0700642 mNetworkLocationProvider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
644 }
645
646 public void setLocationCollector(ILocationCollector collector) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700647 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
648 throw new SecurityException(
649 "Installing location collectors outside of the system is not supported");
650 }
651
Mike Lockwood98cb6672009-04-17 18:03:44 -0400652 mCollector = collector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 }
654
Mike Lockwooda55c3212009-04-15 11:10:11 -0400655 public void setGeocodeProvider(IGeocodeProvider provider) {
656 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
657 throw new SecurityException(
658 "Installing location providers outside of the system is not supported");
659 }
660
661 mGeocodeProvider = provider;
662 }
663
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800664 private boolean isAllowedBySettingsLocked(String provider) {
665 if (mEnabledProviders.contains(provider)) {
666 return true;
667 }
668 if (mDisabledProviders.contains(provider)) {
669 return false;
670 }
671 // Use system settings
672 ContentResolver resolver = mContext.getContentResolver();
673 String allowedProviders = Settings.Secure.getString(resolver,
674 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
675
676 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
677 }
678
679 private void checkPermissionsSafe(String provider) {
680 if (LocationManager.GPS_PROVIDER.equals(provider)
681 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
682 != PackageManager.PERMISSION_GRANTED)) {
683 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
684 }
685 if (LocationManager.NETWORK_PROVIDER.equals(provider)
686 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
687 != PackageManager.PERMISSION_GRANTED)
688 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
689 != PackageManager.PERMISSION_GRANTED)) {
690 throw new SecurityException(
691 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
692 }
693 }
694
695 private boolean isAllowedProviderSafe(String provider) {
696 if (LocationManager.GPS_PROVIDER.equals(provider)
697 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
698 != PackageManager.PERMISSION_GRANTED)) {
699 return false;
700 }
701 if (LocationManager.NETWORK_PROVIDER.equals(provider)
702 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
703 != PackageManager.PERMISSION_GRANTED)
704 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
705 != PackageManager.PERMISSION_GRANTED)) {
706 return false;
707 }
708
709 return true;
710 }
711
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 public List<String> getAllProviders() {
713 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400714 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800715 return _getAllProvidersLocked();
716 }
717 } catch (SecurityException se) {
718 throw se;
719 } catch (Exception e) {
720 Log.e(TAG, "getAllProviders got exception:", e);
721 return null;
722 }
723 }
724
725 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700726 if (LOCAL_LOGV) {
727 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800728 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400729 ArrayList<String> out = new ArrayList<String>(mProviders.size());
730 for (int i = mProviders.size() - 1; i >= 0; i--) {
731 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800732 out.add(p.getName());
733 }
734 return out;
735 }
736
737 public List<String> getProviders(boolean enabledOnly) {
738 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400739 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 return _getProvidersLocked(enabledOnly);
741 }
742 } catch (SecurityException se) {
743 throw se;
744 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700745 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800746 return null;
747 }
748 }
749
750 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700751 if (LOCAL_LOGV) {
752 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400754 ArrayList<String> out = new ArrayList<String>(mProviders.size());
755 for (int i = mProviders.size() - 1; i >= 0; i--) {
756 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800757 String name = p.getName();
758 if (isAllowedProviderSafe(name)) {
759 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
760 continue;
761 }
762 out.add(name);
763 }
764 }
765 return out;
766 }
767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800768 private void updateProvidersLocked() {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400769 for (int i = mProviders.size() - 1; i >= 0; i--) {
770 LocationProviderProxy p = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 boolean isEnabled = p.isEnabled();
772 String name = p.getName();
773 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 if (isEnabled && !shouldBeEnabled) {
776 updateProviderListenersLocked(name, false);
777 } else if (!isEnabled && shouldBeEnabled) {
778 updateProviderListenersLocked(name, true);
779 }
780
781 }
782 }
783
784 private void updateProviderListenersLocked(String provider, boolean enabled) {
785 int listeners = 0;
786
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400787 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 if (p == null) {
789 return;
790 }
791
792 ArrayList<Receiver> deadReceivers = null;
793
794 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
795 if (records != null) {
796 final int N = records.size();
797 for (int i=0; i<N; i++) {
798 UpdateRecord record = records.get(i);
799 // Sends a notification message to the receiver
Mike Lockwood48f17512009-04-23 09:12:08 -0700800 if (!record.mReceiver.callProviderEnabledLocked(provider, enabled)) {
801 if (deadReceivers == null) {
802 deadReceivers = new ArrayList<Receiver>();
803 deadReceivers.add(record.mReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800805 }
806 listeners++;
807 }
808 }
809
810 if (deadReceivers != null) {
811 for (int i=deadReceivers.size()-1; i>=0; i--) {
812 removeUpdatesLocked(deadReceivers.get(i));
813 }
814 }
815
816 if (enabled) {
817 p.enable();
818 if (listeners > 0) {
819 p.setMinTime(getMinTimeLocked(provider));
820 p.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -0700821 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800822 }
823 } else {
824 p.enableLocationTracking(false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 p.disable();
Mike Lockwood61fc2862009-04-21 20:02:52 -0700826 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 }
829
830 private long getMinTimeLocked(String provider) {
831 long minTime = Long.MAX_VALUE;
832 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
833 if (records != null) {
834 for (int i=records.size()-1; i>=0; i--) {
835 minTime = Math.min(minTime, records.get(i).mMinTime);
836 }
837 }
838 return minTime;
839 }
840
841 private class UpdateRecord {
842 final String mProvider;
843 final Receiver mReceiver;
844 final long mMinTime;
845 final float mMinDistance;
846 final int mUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400847 Location mLastFixBroadcast;
848 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800849
850 /**
851 * Note: must be constructed with lock held.
852 */
853 UpdateRecord(String provider, long minTime, float minDistance,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400854 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800855 mProvider = provider;
856 mReceiver = receiver;
857 mMinTime = minTime;
858 mMinDistance = minDistance;
859 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800860
861 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
862 if (records == null) {
863 records = new ArrayList<UpdateRecord>();
864 mRecordsByProvider.put(provider, records);
865 }
866 if (!records.contains(this)) {
867 records.add(this);
868 }
869 }
870
871 /**
872 * Method to be called when a record will no longer be used. Calling this multiple times
873 * must have the same effect as calling it once.
874 */
875 void disposeLocked() {
876 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
877 records.remove(this);
878 }
879
880 @Override
881 public String toString() {
882 return "UpdateRecord{"
883 + Integer.toHexString(System.identityHashCode(this))
884 + " " + mProvider + " " + mReceiver + "}";
885 }
886
887 void dump(PrintWriter pw, String prefix) {
888 pw.println(prefix + this);
889 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
890 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400891 pw.println(prefix + "mUid=" + mUid);
892 pw.println(prefix + "mLastFixBroadcast:");
893 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
894 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 }
896
897 /**
898 * Calls dispose().
899 */
900 @Override protected void finalize() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400901 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800902 disposeLocked();
903 }
904 }
905 }
906
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400907 private Receiver getReceiver(ILocationListener listener) {
908 IBinder binder = listener.asBinder();
909 Receiver receiver = mReceivers.get(binder);
910 if (receiver == null) {
911 receiver = new Receiver(listener);
912 mReceivers.put(binder, receiver);
913
914 try {
915 if (receiver.isListener()) {
916 receiver.getListener().asBinder().linkToDeath(receiver, 0);
917 }
918 } catch (RemoteException e) {
919 Log.e(TAG, "linkToDeath failed:", e);
920 return null;
921 }
922 }
923 return receiver;
924 }
925
926 private Receiver getReceiver(PendingIntent intent) {
927 Receiver receiver = mReceivers.get(intent);
928 if (receiver == null) {
929 receiver = new Receiver(intent);
930 mReceivers.put(intent, receiver);
931 }
932 return receiver;
933 }
934
935 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
936 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
937 if (records != null) {
938 for (int i = records.size() - 1; i >= 0; i--) {
939 UpdateRecord record = records.get(i);
940 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
941 return true;
942 }
943 }
944 }
945 if (LocationManager.GPS_PROVIDER.equals(provider) ||
946 LocationManager.NETWORK_PROVIDER.equals(provider)) {
947 for (ProximityAlert alert : mProximityAlerts.values()) {
948 if (alert.mUid == uid) {
949 return true;
950 }
951 }
952 }
953 return false;
954 }
955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800956 public void requestLocationUpdates(String provider,
957 long minTime, float minDistance, ILocationListener listener) {
958
959 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400960 synchronized (mLock) {
961 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 }
963 } catch (SecurityException se) {
964 throw se;
965 } catch (Exception e) {
966 Log.e(TAG, "requestUpdates got exception:", e);
967 }
968 }
969
970 public void requestLocationUpdatesPI(String provider,
971 long minTime, float minDistance, PendingIntent intent) {
972 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400973 synchronized (mLock) {
974 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800975 }
976 } catch (SecurityException se) {
977 throw se;
978 } catch (Exception e) {
979 Log.e(TAG, "requestUpdates got exception:", e);
980 }
981 }
982
983 private void requestLocationUpdatesLocked(String provider,
984 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700985 if (LOCAL_LOGV) {
986 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800987 }
988
Mike Lockwood15e3d0f2009-05-01 07:53:28 -0400989 LocationProviderProxy proxy = mProvidersByName.get(provider);
990 if (proxy == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 throw new IllegalArgumentException("provider=" + provider);
992 }
993
994 checkPermissionsSafe(provider);
995
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 // so wakelock calls will succeed
997 final int callingUid = Binder.getCallingUid();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400998 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800999 long identity = Binder.clearCallingIdentity();
1000 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001001 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
1002 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 if (oldRecord != null) {
1004 oldRecord.disposeLocked();
1005 }
1006
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001007 if (newUid) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001008 proxy.addListener(callingUid);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001009 }
1010
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001011 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1012 if (isProviderEnabled) {
1013 long minTimeForProvider = getMinTimeLocked(provider);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001014 proxy.setMinTime(minTimeForProvider);
1015 proxy.enableLocationTracking(true);
Mike Lockwood61fc2862009-04-21 20:02:52 -07001016 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 } else {
Mike Lockwood48f17512009-04-23 09:12:08 -07001018 // Notify the listener that updates are currently disabled
1019 receiver.callProviderEnabledLocked(provider, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001020 }
1021 } finally {
1022 Binder.restoreCallingIdentity(identity);
1023 }
1024 }
1025
1026 public void removeUpdates(ILocationListener listener) {
1027 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001028 synchronized (mLock) {
1029 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 }
1031 } catch (SecurityException se) {
1032 throw se;
1033 } catch (Exception e) {
1034 Log.e(TAG, "removeUpdates got exception:", e);
1035 }
1036 }
1037
1038 public void removeUpdatesPI(PendingIntent intent) {
1039 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001040 synchronized (mLock) {
1041 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001042 }
1043 } catch (SecurityException se) {
1044 throw se;
1045 } catch (Exception e) {
1046 Log.e(TAG, "removeUpdates got exception:", e);
1047 }
1048 }
1049
1050 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001051 if (LOCAL_LOGV) {
1052 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054
1055 // so wakelock calls will succeed
1056 final int callingUid = Binder.getCallingUid();
1057 long identity = Binder.clearCallingIdentity();
1058 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001059 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1060 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 }
1062
1063 // Record which providers were associated with this listener
1064 HashSet<String> providers = new HashSet<String>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001065 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 if (oldRecords != null) {
1067 // Call dispose() on the obsolete update records.
1068 for (UpdateRecord record : oldRecords.values()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001069 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001070 LocationProviderProxy proxy = mProvidersByName.get(record.mProvider);
1071 if (proxy != null) {
1072 proxy.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 }
1074 }
1075 record.disposeLocked();
1076 }
1077 // Accumulate providers
1078 providers.addAll(oldRecords.keySet());
1079 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001080
1081 // See if the providers associated with this listener have any
1082 // other listeners; if one does, inform it of the new smallest minTime
1083 // value; if one does not, disable location tracking for it
1084 for (String provider : providers) {
1085 // If provider is already disabled, don't need to do anything
1086 if (!isAllowedBySettingsLocked(provider)) {
1087 continue;
1088 }
1089
1090 boolean hasOtherListener = false;
1091 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1092 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1093 hasOtherListener = true;
1094 }
1095
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001096 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 if (p != null) {
1098 if (hasOtherListener) {
1099 p.setMinTime(getMinTimeLocked(provider));
1100 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001101 p.enableLocationTracking(false);
1102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 }
1104 }
1105
Mike Lockwood61fc2862009-04-21 20:02:52 -07001106 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 } finally {
1108 Binder.restoreCallingIdentity(identity);
1109 }
1110 }
1111
1112 public boolean addGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001113 if (mGpsStatusProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 return false;
1115 }
1116 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
1117 PackageManager.PERMISSION_GRANTED) {
1118 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1119 }
1120
1121 try {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001122 mGpsStatusProvider.addGpsStatusListener(listener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001123 } catch (RemoteException e) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001124 Log.e(TAG, "mGpsStatusProvider.addGpsStatusListener failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001125 return false;
1126 }
1127 return true;
1128 }
1129
1130 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001131 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001132 try {
1133 mGpsStatusProvider.removeGpsStatusListener(listener);
1134 } catch (Exception e) {
1135 Log.e(TAG, "mGpsStatusProvider.removeGpsStatusListener failed", e);
1136 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 }
1138 }
1139
1140 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1141 // first check for permission to the provider
1142 checkPermissionsSafe(provider);
1143 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1144 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1145 != PackageManager.PERMISSION_GRANTED)) {
1146 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1147 }
1148
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001149 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001150 LocationProviderProxy proxy = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 if (provider == null) {
1152 return false;
1153 }
1154
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001155 return proxy.sendExtraCommand(command, extras);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001156 }
1157 }
1158
1159 class ProximityAlert {
1160 final int mUid;
1161 final double mLatitude;
1162 final double mLongitude;
1163 final float mRadius;
1164 final long mExpiration;
1165 final PendingIntent mIntent;
1166 final Location mLocation;
1167
1168 public ProximityAlert(int uid, double latitude, double longitude,
1169 float radius, long expiration, PendingIntent intent) {
1170 mUid = uid;
1171 mLatitude = latitude;
1172 mLongitude = longitude;
1173 mRadius = radius;
1174 mExpiration = expiration;
1175 mIntent = intent;
1176
1177 mLocation = new Location("");
1178 mLocation.setLatitude(latitude);
1179 mLocation.setLongitude(longitude);
1180 }
1181
1182 long getExpiration() {
1183 return mExpiration;
1184 }
1185
1186 PendingIntent getIntent() {
1187 return mIntent;
1188 }
1189
1190 boolean isInProximity(double latitude, double longitude) {
1191 Location loc = new Location("");
1192 loc.setLatitude(latitude);
1193 loc.setLongitude(longitude);
1194
1195 double radius = loc.distanceTo(mLocation);
1196 return radius <= mRadius;
1197 }
1198
1199 @Override
1200 public String toString() {
1201 return "ProximityAlert{"
1202 + Integer.toHexString(System.identityHashCode(this))
1203 + " uid " + mUid + mIntent + "}";
1204 }
1205
1206 void dump(PrintWriter pw, String prefix) {
1207 pw.println(prefix + this);
1208 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1209 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1210 pw.println(prefix + "mIntent=" + mIntent);
1211 pw.println(prefix + "mLocation:");
1212 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1213 }
1214 }
1215
1216 // Listener for receiving locations to trigger proximity alerts
Mike Lockwood48f17512009-04-23 09:12:08 -07001217 class ProximityListener extends ILocationListener.Stub implements PendingIntent.OnFinished {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218
1219 boolean isGpsAvailable = false;
1220
1221 // Note: this is called with the lock held.
1222 public void onLocationChanged(Location loc) {
1223
1224 // If Gps is available, then ignore updates from NetworkLocationProvider
1225 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1226 isGpsAvailable = true;
1227 }
1228 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1229 return;
1230 }
1231
1232 // Process proximity alerts
1233 long now = System.currentTimeMillis();
1234 double latitude = loc.getLatitude();
1235 double longitude = loc.getLongitude();
1236 ArrayList<PendingIntent> intentsToRemove = null;
1237
1238 for (ProximityAlert alert : mProximityAlerts.values()) {
1239 PendingIntent intent = alert.getIntent();
1240 long expiration = alert.getExpiration();
1241
1242 if ((expiration == -1) || (now <= expiration)) {
1243 boolean entered = mProximitiesEntered.contains(alert);
1244 boolean inProximity =
1245 alert.isInProximity(latitude, longitude);
1246 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001247 if (LOCAL_LOGV) {
1248 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 }
1250 mProximitiesEntered.add(alert);
1251 Intent enteredIntent = new Intent();
1252 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1253 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001254 synchronized (mLock) {
1255 // synchronize to ensure incrementPendingBroadcastsLocked()
1256 // is called before decrementPendingBroadcasts()
1257 intent.send(mContext, 0, enteredIntent, this, mLocationHandler);
1258 // call this after broadcasting so we do not increment
1259 // if we throw an exeption.
1260 incrementPendingBroadcastsLocked();
1261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001262 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001263 if (LOCAL_LOGV) {
1264 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001265 }
1266 if (intentsToRemove == null) {
1267 intentsToRemove = new ArrayList<PendingIntent>();
1268 }
1269 intentsToRemove.add(intent);
1270 }
1271 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001272 if (LOCAL_LOGV) {
1273 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001274 }
1275 mProximitiesEntered.remove(alert);
1276 Intent exitedIntent = new Intent();
1277 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1278 try {
Mike Lockwood48f17512009-04-23 09:12:08 -07001279 synchronized (mLock) {
1280 // synchronize to ensure incrementPendingBroadcastsLocked()
1281 // is called before decrementPendingBroadcasts()
1282 intent.send(mContext, 0, exitedIntent, this, mLocationHandler);
1283 // call this after broadcasting so we do not increment
1284 // if we throw an exeption.
1285 incrementPendingBroadcastsLocked();
1286 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001288 if (LOCAL_LOGV) {
1289 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 }
1291 if (intentsToRemove == null) {
1292 intentsToRemove = new ArrayList<PendingIntent>();
1293 }
1294 intentsToRemove.add(intent);
1295 }
1296 }
1297 } else {
1298 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001299 if (LOCAL_LOGV) {
1300 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001301 }
1302 if (intentsToRemove == null) {
1303 intentsToRemove = new ArrayList<PendingIntent>();
1304 }
1305 intentsToRemove.add(alert.getIntent());
1306 }
1307 }
1308
1309 // Remove expired alerts
1310 if (intentsToRemove != null) {
1311 for (PendingIntent i : intentsToRemove) {
1312 mProximityAlerts.remove(i);
1313 ProximityAlert alert = mProximityAlerts.get(i);
1314 mProximitiesEntered.remove(alert);
1315 }
1316 }
1317
1318 }
1319
1320 // Note: this is called with the lock held.
1321 public void onProviderDisabled(String provider) {
1322 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1323 isGpsAvailable = false;
1324 }
1325 }
1326
1327 // Note: this is called with the lock held.
1328 public void onProviderEnabled(String provider) {
1329 // ignore
1330 }
1331
1332 // Note: this is called with the lock held.
1333 public void onStatusChanged(String provider, int status, Bundle extras) {
1334 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1335 (status != LocationProvider.AVAILABLE)) {
1336 isGpsAvailable = false;
1337 }
1338 }
Mike Lockwood48f17512009-04-23 09:12:08 -07001339
1340 public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1341 int resultCode, String resultData, Bundle resultExtras) {
1342 decrementPendingBroadcasts();
1343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 }
1345
1346 public void addProximityAlert(double latitude, double longitude,
1347 float radius, long expiration, PendingIntent intent) {
1348 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001349 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1351 }
1352 } catch (SecurityException se) {
1353 throw se;
1354 } catch (Exception e) {
1355 Log.e(TAG, "addProximityAlert got exception:", e);
1356 }
1357 }
1358
1359 private void addProximityAlertLocked(double latitude, double longitude,
1360 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001361 if (LOCAL_LOGV) {
1362 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001363 ", longitude = " + longitude +
1364 ", expiration = " + expiration +
1365 ", intent = " + intent);
1366 }
1367
1368 // Require ability to access all providers for now
1369 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1370 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1371 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1372 }
1373
1374 if (expiration != -1) {
1375 expiration += System.currentTimeMillis();
1376 }
1377 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1378 latitude, longitude, radius, expiration, intent);
1379 mProximityAlerts.put(intent, alert);
1380
Mike Lockwood48f17512009-04-23 09:12:08 -07001381 if (mProximityReceiver == null) {
1382 mProximityListener = new ProximityListener();
1383 mProximityReceiver = new Receiver(mProximityListener);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001385 LocationProviderProxy provider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001387 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 }
1389
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001390 provider = mProvidersByName.get(LocationManager.NETWORK_PROVIDER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 if (provider != null) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001392 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001394 }
1395 }
1396
1397 public void removeProximityAlert(PendingIntent intent) {
1398 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001399 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001400 removeProximityAlertLocked(intent);
1401 }
1402 } catch (SecurityException se) {
1403 throw se;
1404 } catch (Exception e) {
1405 Log.e(TAG, "removeProximityAlert got exception:", e);
1406 }
1407 }
1408
1409 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001410 if (LOCAL_LOGV) {
1411 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 }
1413
1414 mProximityAlerts.remove(intent);
1415 if (mProximityAlerts.size() == 0) {
Mike Lockwood48f17512009-04-23 09:12:08 -07001416 removeUpdatesLocked(mProximityReceiver);
1417 mProximityReceiver = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001418 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419 }
1420 }
1421
1422 /**
1423 * @return null if the provider does not exits
1424 * @throw SecurityException if the provider is not allowed to be
1425 * accessed by the caller
1426 */
1427 public Bundle getProviderInfo(String provider) {
1428 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001429 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001430 return _getProviderInfoLocked(provider);
1431 }
1432 } catch (SecurityException se) {
1433 throw se;
1434 } catch (Exception e) {
1435 Log.e(TAG, "_getProviderInfo got exception:", e);
1436 return null;
1437 }
1438 }
1439
1440 private Bundle _getProviderInfoLocked(String provider) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001441 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001442 if (p == null) {
1443 return null;
1444 }
1445
1446 checkPermissionsSafe(provider);
1447
1448 Bundle b = new Bundle();
1449 b.putBoolean("network", p.requiresNetwork());
1450 b.putBoolean("satellite", p.requiresSatellite());
1451 b.putBoolean("cell", p.requiresCell());
1452 b.putBoolean("cost", p.hasMonetaryCost());
1453 b.putBoolean("altitude", p.supportsAltitude());
1454 b.putBoolean("speed", p.supportsSpeed());
1455 b.putBoolean("bearing", p.supportsBearing());
1456 b.putInt("power", p.getPowerRequirement());
1457 b.putInt("accuracy", p.getAccuracy());
1458
1459 return b;
1460 }
1461
1462 public boolean isProviderEnabled(String provider) {
1463 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001464 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001465 return _isProviderEnabledLocked(provider);
1466 }
1467 } catch (SecurityException se) {
1468 throw se;
1469 } catch (Exception e) {
1470 Log.e(TAG, "isProviderEnabled got exception:", e);
1471 return false;
1472 }
1473 }
1474
Mike Lockwood4e50b782009-04-03 08:24:43 -07001475 public void setLocation(Location location) {
1476 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1477 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1478 mLocationHandler.sendMessageAtFrontOfQueue(m);
1479 }
1480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001481 private boolean _isProviderEnabledLocked(String provider) {
1482 checkPermissionsSafe(provider);
1483
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001484 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001485 if (p == null) {
1486 throw new IllegalArgumentException("provider=" + provider);
1487 }
1488 return isAllowedBySettingsLocked(provider);
1489 }
1490
1491 public Location getLastKnownLocation(String provider) {
1492 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001493 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001494 return _getLastKnownLocationLocked(provider);
1495 }
1496 } catch (SecurityException se) {
1497 throw se;
1498 } catch (Exception e) {
1499 Log.e(TAG, "getLastKnownLocation got exception:", e);
1500 return null;
1501 }
1502 }
1503
1504 private Location _getLastKnownLocationLocked(String provider) {
1505 checkPermissionsSafe(provider);
1506
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001507 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001508 if (p == null) {
1509 throw new IllegalArgumentException("provider=" + provider);
1510 }
1511
1512 if (!isAllowedBySettingsLocked(provider)) {
1513 return null;
1514 }
1515
1516 Location location = mLastKnownLocation.get(provider);
1517 if (location == null) {
1518 // Get the persistent last known location for the provider
1519 location = readLastKnownLocationLocked(provider);
1520 if (location != null) {
1521 mLastKnownLocation.put(provider, location);
1522 }
1523 }
1524
1525 return location;
1526 }
1527
1528 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1529 // Always broadcast the first update
1530 if (lastLoc == null) {
1531 return true;
1532 }
1533
1534 // Don't broadcast same location again regardless of condition
1535 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1536 if (loc.getTime() == lastLoc.getTime()) {
1537 return false;
1538 }
1539
1540 // Check whether sufficient distance has been traveled
1541 double minDistance = record.mMinDistance;
1542 if (minDistance > 0.0) {
1543 if (loc.distanceTo(lastLoc) <= minDistance) {
1544 return false;
1545 }
1546 }
1547
1548 return true;
1549 }
1550
Mike Lockwood4e50b782009-04-03 08:24:43 -07001551 private void handleLocationChangedLocked(Location location) {
1552 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1554 if (records == null || records.size() == 0) {
1555 return;
1556 }
1557
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001558 LocationProviderProxy p = mProvidersByName.get(provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001559 if (p == null) {
1560 return;
1561 }
1562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001563 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001564 Location lastLocation = mLastKnownLocation.get(provider);
1565 if (lastLocation == null) {
1566 mLastKnownLocation.put(provider, new Location(location));
1567 } else {
1568 lastLocation.set(location);
1569 }
1570 writeLastKnownLocationLocked(provider, location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001572 if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001573 mWakeLockNetworkReceived = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001574 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001575 // Gps location received signal is in NetworkStateBroadcastReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576
1577 // Fetch latest status update time
1578 long newStatusUpdateTime = p.getStatusUpdateTime();
1579
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001580 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001581 Bundle extras = new Bundle();
1582 int status = p.getStatus(extras);
1583
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001584 ArrayList<Receiver> deadReceivers = null;
1585
1586 // Broadcast location or status to all listeners
1587 final int N = records.size();
1588 for (int i=0; i<N; i++) {
1589 UpdateRecord r = records.get(i);
1590 Receiver receiver = r.mReceiver;
1591
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001592 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001593 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1594 if (lastLoc == null) {
1595 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001596 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001597 } else {
1598 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001599 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001600 if (!receiver.callLocationChangedLocked(location)) {
1601 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1602 if (deadReceivers == null) {
1603 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001604 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001605 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001606 }
1607 }
1608
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001609 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001610 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1611 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1612
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001613 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001614 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1615 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1616 if (deadReceivers == null) {
1617 deadReceivers = new ArrayList<Receiver>();
1618 }
1619 if (!deadReceivers.contains(receiver)) {
1620 deadReceivers.add(receiver);
1621 }
1622 }
1623 }
1624 }
1625
1626 if (deadReceivers != null) {
1627 for (int i=deadReceivers.size()-1; i>=0; i--) {
1628 removeUpdatesLocked(deadReceivers.get(i));
1629 }
1630 }
1631 }
1632
1633 private class LocationWorkerHandler extends Handler {
1634
1635 @Override
1636 public void handleMessage(Message msg) {
1637 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001638 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1639 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001640
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001641 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001642 Location location = (Location) msg.obj;
Mike Lockwood98cb6672009-04-17 18:03:44 -04001643
1644 if (mCollector != null &&
1645 LocationManager.GPS_PROVIDER.equals(location.getProvider())) {
1646 try {
1647 mCollector.updateLocation(location);
1648 } catch (RemoteException e) {
1649 Log.w(TAG, "mCollector.updateLocation failed");
1650 }
1651 }
1652
Mike Lockwood4e50b782009-04-03 08:24:43 -07001653 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001654 if (!isAllowedBySettingsLocked(provider)) {
1655 return;
1656 }
1657
Mike Lockwooda0e3cd32009-04-21 21:27:33 -07001658 handleLocationChangedLocked(location);
Mike Lockwood61fc2862009-04-21 20:02:52 -07001659 updateWakelockStatusLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001661 }
1662 } catch (Exception e) {
1663 // Log, don't crash!
1664 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1665 }
1666 }
1667 }
1668
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001669 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1670 @Override public void onReceive(Context context, Intent intent) {
1671 String action = intent.getAction();
1672
1673 if (action.equals(ALARM_INTENT)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001674 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 log("PowerStateBroadcastReceiver: Alarm received");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 // Have to do this immediately, rather than posting a
1677 // message, so we execute our code while the system
1678 // is holding a wake lock until the alarm broadcast
1679 // is finished.
1680 acquireWakeLockLocked();
1681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001682 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1683 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001684 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1686 if (uid >= 0) {
1687 ArrayList<Receiver> removedRecs = null;
1688 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1689 for (int j=i.size()-1; j>=0; j--) {
1690 UpdateRecord ur = i.get(j);
1691 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1692 if (removedRecs == null) {
1693 removedRecs = new ArrayList<Receiver>();
1694 }
1695 if (!removedRecs.contains(ur.mReceiver)) {
1696 removedRecs.add(ur.mReceiver);
1697 }
1698 }
1699 }
1700 }
1701 ArrayList<ProximityAlert> removedAlerts = null;
1702 for (ProximityAlert i : mProximityAlerts.values()) {
1703 if (i.mUid == uid) {
1704 if (removedAlerts == null) {
1705 removedAlerts = new ArrayList<ProximityAlert>();
1706 }
1707 if (!removedAlerts.contains(i)) {
1708 removedAlerts.add(i);
1709 }
1710 }
1711 }
1712 if (removedRecs != null) {
1713 for (int i=removedRecs.size()-1; i>=0; i--) {
1714 removeUpdatesLocked(removedRecs.get(i));
1715 }
1716 }
1717 if (removedAlerts != null) {
1718 for (int i=removedAlerts.size()-1; i>=0; i--) {
1719 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1720 }
1721 }
1722 }
1723 }
1724 }
1725 }
1726 }
1727
1728 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1729 @Override public void onReceive(Context context, Intent intent) {
1730 String action = intent.getAction();
1731
Mike Lockwoodf113fbe2009-04-06 05:17:28 -07001732 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001733 boolean noConnectivity =
1734 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1735 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001736 mNetworkState = LocationProvider.AVAILABLE;
1737 } else {
1738 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 }
1740
1741 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001742 synchronized (mLock) {
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001743 for (int i = mProviders.size() - 1; i >= 0; i--) {
1744 LocationProviderProxy provider = mProviders.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001745 if (provider.requiresNetwork()) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 provider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 }
1748 }
1749 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
1751
1752 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
1753 false);
1754
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001755 synchronized (mLock) {
Mike Lockwood98cb6672009-04-17 18:03:44 -04001756 if (!enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 // When GPS is disabled, we are OK to release wake-lock
1758 mWakeLockGpsReceived = true;
1759 }
1760 }
1761 }
1762
1763 }
1764 }
1765
1766 // Wake locks
1767
Mike Lockwood61fc2862009-04-21 20:02:52 -07001768 private void updateWakelockStatusLocked() {
1769 log("updateWakelockStatus()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001771 long callerId = Binder.clearCallingIdentity();
1772
Mike Lockwood48f17512009-04-23 09:12:08 -07001773 boolean needsLock = (mPendingBroadcasts > 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001774 long minTime = Integer.MAX_VALUE;
1775
1776 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
1777 needsLock = true;
1778 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
1779 }
1780
1781 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
1782 needsLock = true;
1783 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001784 }
1785
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001786 PendingIntent sender =
1787 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
1788
1789 // Cancel existing alarm
1790 log("Cancelling existing alarm");
1791 mAlarmManager.cancel(sender);
1792
Mike Lockwood61fc2862009-04-21 20:02:52 -07001793 if (needsLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001794 long now = SystemClock.elapsedRealtime();
1795 mAlarmManager.set(
1796 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
1797 mAlarmInterval = minTime;
1798 log("Creating a new wakelock alarm with minTime = " + minTime);
1799 } else {
1800 log("No need for alarm");
1801 mAlarmInterval = -1;
1802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001803 releaseWakeLockLocked();
1804 }
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001805 Binder.restoreCallingIdentity(callerId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807
1808 private void acquireWakeLockLocked() {
1809 try {
1810 acquireWakeLockXLocked();
1811 } catch (Exception e) {
1812 // This is to catch a runtime exception thrown when we try to release an
1813 // already released lock.
1814 Log.e(TAG, "exception in acquireWakeLock()", e);
1815 }
1816 }
1817
1818 private void acquireWakeLockXLocked() {
1819 if (mWakeLock.isHeld()) {
1820 log("Must release wakelock before acquiring");
1821 mWakeLockAcquireTime = 0;
1822 mWakeLock.release();
1823 }
1824
1825 boolean networkActive = (mNetworkLocationProvider != null)
1826 && mNetworkLocationProvider.isLocationTracking();
1827 boolean gpsActive = (mGpsLocationProvider != null)
1828 && mGpsLocationProvider.isLocationTracking();
1829
1830 boolean needsLock = networkActive || gpsActive;
1831 if (!needsLock) {
1832 log("No need for Lock!");
1833 return;
1834 }
1835
1836 mWakeLockGpsReceived = !gpsActive;
1837 mWakeLockNetworkReceived = !networkActive;
1838
1839 // Acquire wake lock
1840 mWakeLock.acquire();
1841 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
1842 log("Acquired wakelock");
1843
Mike Lockwood6de31542009-04-21 12:13:35 -07001844 if (mNetworkLocationProvider != null) {
1845 mNetworkLocationProvider.wakeLockAcquired();
1846 }
1847 if (mGpsLocationProvider != null) {
1848 mGpsLocationProvider.wakeLockAcquired();
1849 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001850 }
1851
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 private void releaseWakeLockLocked() {
1853 try {
1854 releaseWakeLockXLocked();
1855 } catch (Exception e) {
1856 // This is to catch a runtime exception thrown when we try to release an
1857 // already released lock.
1858 Log.e(TAG, "exception in releaseWakeLock()", e);
1859 }
1860 }
1861
1862 private void releaseWakeLockXLocked() {
Mike Lockwood6de31542009-04-21 12:13:35 -07001863 if (mNetworkLocationProvider != null) {
1864 mNetworkLocationProvider.wakeLockReleased();
1865 }
1866 if (mGpsLocationProvider != null) {
1867 mGpsLocationProvider.wakeLockReleased();
1868 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001869
1870 // Release wake lock
1871 mWakeLockAcquireTime = 0;
1872 if (mWakeLock.isHeld()) {
1873 log("Released wakelock");
1874 mWakeLock.release();
1875 } else {
1876 log("Can't release wakelock again!");
1877 }
1878 }
1879
Mike Lockwood48f17512009-04-23 09:12:08 -07001880 private void incrementPendingBroadcastsLocked() {
1881 if (mPendingBroadcasts++ == 0) {
1882 updateWakelockStatusLocked();
1883 }
1884 }
1885
1886 private void decrementPendingBroadcasts() {
1887 synchronized (mLock) {
1888 if (--mPendingBroadcasts == 0) {
1889 updateWakelockStatusLocked();
1890 }
1891 }
1892 }
1893
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001894 // Geocoder
1895
1896 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001897 String language, String country, String variant, String appName, List<Address> addrs) {
1898 if (mGeocodeProvider != null) {
1899 try {
1900 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1901 variant, appName, addrs);
1902 } catch (RemoteException e) {
1903 Log.e(TAG, "getFromLocation failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001904 }
1905 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001906 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001907 }
1908
Mike Lockwooda55c3212009-04-15 11:10:11 -04001909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001910 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001911 double lowerLeftLatitude, double lowerLeftLongitude,
1912 double upperRightLatitude, double upperRightLongitude, int maxResults,
1913 String language, String country, String variant, String appName, List<Address> addrs) {
1914
1915 if (mGeocodeProvider != null) {
1916 try {
1917 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1918 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1919 maxResults, language, country, variant, appName, addrs);
1920 } catch (RemoteException e) {
1921 Log.e(TAG, "getFromLocationName failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001922 }
1923 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001924 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001925 }
1926
1927 // Mock Providers
1928
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001929 private void checkMockPermissionsSafe() {
1930 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
1931 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
1932 if (!allowMocks) {
1933 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
1934 }
1935
1936 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
1937 PackageManager.PERMISSION_GRANTED) {
1938 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
1939 }
1940 }
1941
1942 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
1943 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
1944 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
1945 checkMockPermissionsSafe();
1946
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001947 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001948 MockProvider provider = new MockProvider(name, this,
1949 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001950 requiresCell, hasMonetaryCost, supportsAltitude,
1951 supportsSpeed, supportsBearing, powerRequirement, accuracy);
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001952 if (mProvidersByName.get(name) != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001953 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
1954 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001955 addProvider(new LocationProviderProxy(name, provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001956 mMockProviders.put(name, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001957 updateProvidersLocked();
1958 }
1959 }
1960
1961 public void removeTestProvider(String provider) {
1962 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001963 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001964 MockProvider mockProvider = mMockProviders.get(provider);
1965 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001966 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1967 }
Mike Lockwood15e3d0f2009-05-01 07:53:28 -04001968 removeProvider(mProvidersByName.get(provider));
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001969 mMockProviders.remove(mockProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001970 updateProvidersLocked();
1971 }
1972 }
1973
1974 public void setTestProviderLocation(String provider, Location loc) {
1975 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001976 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001977 MockProvider mockProvider = mMockProviders.get(provider);
1978 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001979 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1980 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001981 mockProvider.setLocation(loc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 }
1983 }
1984
1985 public void clearTestProviderLocation(String provider) {
1986 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001987 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001988 MockProvider mockProvider = mMockProviders.get(provider);
1989 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
1991 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001992 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 }
1994 }
1995
1996 public void setTestProviderEnabled(String provider, boolean enabled) {
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 }
2003 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002004 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002005 mEnabledProviders.add(provider);
2006 mDisabledProviders.remove(provider);
2007 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002008 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002009 mEnabledProviders.remove(provider);
2010 mDisabledProviders.add(provider);
2011 }
2012 updateProvidersLocked();
2013 }
2014 }
2015
2016 public void clearTestProviderEnabled(String provider) {
2017 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002018 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002019 MockProvider mockProvider = mMockProviders.get(provider);
2020 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002021 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2022 }
2023 mEnabledProviders.remove(provider);
2024 mDisabledProviders.remove(provider);
2025 updateProvidersLocked();
2026 }
2027 }
2028
2029 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2030 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002031 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002032 MockProvider mockProvider = mMockProviders.get(provider);
2033 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002034 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2035 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002036 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002037 }
2038 }
2039
2040 public void clearTestProviderStatus(String provider) {
2041 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002042 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002043 MockProvider mockProvider = mMockProviders.get(provider);
2044 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002045 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2046 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002047 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002048 }
2049 }
2050
2051 private void log(String log) {
2052 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2053 Log.d(TAG, log);
2054 }
2055 }
2056
2057 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2058 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2059 != PackageManager.PERMISSION_GRANTED) {
2060 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2061 + Binder.getCallingPid()
2062 + ", uid=" + Binder.getCallingUid());
2063 return;
2064 }
2065
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002066 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002067 pw.println("Current Location Manager state:");
2068 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2069 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002070 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002071 pw.println(" mCollector=" + mCollector);
2072 pw.println(" mAlarmInterval=" + mAlarmInterval
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2074 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2075 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002077 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002079 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002080 }
2081 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002082 for (Receiver i : mReceivers.values()) {
2083 pw.println(" " + i + ":");
2084 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002085 pw.println(" " + j.getKey() + ":");
2086 j.getValue().dump(pw, " ");
2087 }
2088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002089 pw.println(" Records by Provider:");
2090 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2091 : mRecordsByProvider.entrySet()) {
2092 pw.println(" " + i.getKey() + ":");
2093 for (UpdateRecord j : i.getValue()) {
2094 pw.println(" " + j + ":");
2095 j.dump(pw, " ");
2096 }
2097 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002098 pw.println(" Last Known Locations:");
2099 for (Map.Entry<String, Location> i
2100 : mLastKnownLocation.entrySet()) {
2101 pw.println(" " + i.getKey() + ":");
2102 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2103 }
2104 if (mProximityAlerts.size() > 0) {
2105 pw.println(" Proximity Alerts:");
2106 for (Map.Entry<PendingIntent, ProximityAlert> i
2107 : mProximityAlerts.entrySet()) {
2108 pw.println(" " + i.getKey() + ":");
2109 i.getValue().dump(pw, " ");
2110 }
2111 }
2112 if (mProximitiesEntered.size() > 0) {
2113 pw.println(" Proximities Entered:");
2114 for (ProximityAlert i : mProximitiesEntered) {
2115 pw.println(" " + i + ":");
2116 i.dump(pw, " ");
2117 }
2118 }
Mike Lockwood48f17512009-04-23 09:12:08 -07002119 pw.println(" mProximityReceiver=" + mProximityReceiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002120 pw.println(" mProximityListener=" + mProximityListener);
2121 if (mEnabledProviders.size() > 0) {
2122 pw.println(" Enabled Providers:");
2123 for (String i : mEnabledProviders) {
2124 pw.println(" " + i);
2125 }
2126
2127 }
2128 if (mDisabledProviders.size() > 0) {
2129 pw.println(" Disabled Providers:");
2130 for (String i : mDisabledProviders) {
2131 pw.println(" " + i);
2132 }
2133
2134 }
2135 if (mMockProviders.size() > 0) {
2136 pw.println(" Mock Providers:");
2137 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002138 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002139 }
2140 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002141 }
2142 }
2143}