blob: c91e21cb15ed8bf5e18714286eeaeedcea49941f [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 Lockwoode932f7f2009-04-06 10:51:26 -070049import android.location.ILocationCollector;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.location.ILocationListener;
51import android.location.ILocationManager;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070052import android.location.ILocationProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.location.Location;
54import android.location.LocationManager;
55import android.location.LocationProvider;
56import android.location.LocationProviderImpl;
57import android.net.ConnectivityManager;
58import android.net.Uri;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.net.wifi.WifiManager;
60import android.os.Binder;
61import android.os.Bundle;
62import android.os.Handler;
63import android.os.IBinder;
64import 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.telephony.TelephonyManager;
71import android.util.Config;
72import android.util.Log;
73import android.util.PrintWriterPrinter;
74import android.util.SparseIntArray;
75
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080076import com.android.internal.location.GpsLocationProvider;
Mike Lockwoode932f7f2009-04-06 10:51:26 -070077import com.android.internal.location.LocationProviderProxy;
Mike Lockwood7ec434e2009-03-27 07:46:48 -070078import com.android.internal.location.MockProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import com.android.internal.location.TrackProvider;
80import com.android.server.am.BatteryStatsService;
81
82/**
83 * The service class that manages LocationProviders and issues location
84 * updates and alerts.
85 *
86 * {@hide}
87 */
Mike Lockwoode932f7f2009-04-06 10:51:26 -070088public class LocationManagerService extends ILocationManager.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 private static final String TAG = "LocationManagerService";
The Android Open Source Project10592532009-03-18 17:39:46 -070090 private static final boolean LOCAL_LOGV = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091
92 // Minimum time interval between last known location writes, in milliseconds.
93 private static final long MIN_LAST_KNOWN_LOCATION_TIME = 60L * 1000L;
94
95 // Max time to hold wake lock for, in milliseconds.
96 private static final long MAX_TIME_FOR_WAKE_LOCK = 60 * 1000L;
97
98 // Time to wait after releasing a wake lock for clients to process location update,
99 // in milliseconds.
100 private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L;
101
102 // The last time a location was written, by provider name.
103 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
104
105 private static final Pattern PATTERN_COMMA = Pattern.compile(",");
106
107 private static final String ACCESS_FINE_LOCATION =
108 android.Manifest.permission.ACCESS_FINE_LOCATION;
109 private static final String ACCESS_COARSE_LOCATION =
110 android.Manifest.permission.ACCESS_COARSE_LOCATION;
111 private static final String ACCESS_MOCK_LOCATION =
112 android.Manifest.permission.ACCESS_MOCK_LOCATION;
113 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
114 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
115
116 // Set of providers that are explicitly enabled
117 private final Set<String> mEnabledProviders = new HashSet<String>();
118
119 // Set of providers that are explicitly disabled
120 private final Set<String> mDisabledProviders = new HashSet<String>();
121
122 // Locations, status values, and extras for mock providers
Mike Lockwood7ec434e2009-03-27 07:46:48 -0700123 private final HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124
125 private static boolean sProvidersLoaded = false;
126
127 private final Context mContext;
128 private GpsLocationProvider mGpsLocationProvider;
129 private boolean mGpsNavigating;
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700130 private LocationProviderProxy mNetworkLocationProvider;
Mike Lockwooda55c3212009-04-15 11:10:11 -0400131 private IGeocodeProvider mGeocodeProvider;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private LocationWorkerHandler mLocationHandler;
133
134 // Handler messages
Mike Lockwood4e50b782009-04-03 08:24:43 -0700135 private static final int MESSAGE_LOCATION_CHANGED = 1;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
137 private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
139 // Alarm manager and wakelock variables
140 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
141 private final static String WAKELOCK_KEY = "LocationManagerService";
142 private final static String WIFILOCK_KEY = "LocationManagerService";
143 private AlarmManager mAlarmManager;
144 private long mAlarmInterval = 0;
145 private boolean mScreenOn = true;
146 private PowerManager.WakeLock mWakeLock = null;
147 private WifiManager.WifiLock mWifiLock = null;
148 private long mWakeLockAcquireTime = 0;
149 private boolean mWakeLockGpsReceived = true;
150 private boolean mWakeLockNetworkReceived = true;
151 private boolean mWifiWakeLockAcquired = false;
152 private boolean mCellWakeLockAcquired = false;
153
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800154 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400155 * List of all receivers.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400157 private final HashMap<Object, Receiver> mReceivers = new HashMap<Object, Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800158
159 /**
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400160 * Object used internally for synchronization
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 */
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400162 private final Object mLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
164 /**
165 * Mapping from provider name to all its UpdateRecords
166 */
167 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
168 new HashMap<String,ArrayList<UpdateRecord>>();
169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 // Proximity listeners
171 private Receiver mProximityListener = null;
172 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
173 new HashMap<PendingIntent,ProximityAlert>();
174 private HashSet<ProximityAlert> mProximitiesEntered =
175 new HashSet<ProximityAlert>();
176
177 // Last known location for each provider
178 private HashMap<String,Location> mLastKnownLocation =
179 new HashMap<String,Location>();
180
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 // Last known cell service state
182 private TelephonyManager mTelephonyManager;
183
184 // Location collector
185 private ILocationCollector mCollector;
186
187 // Wifi Manager
188 private WifiManager mWifiManager;
189
The Android Open Source Project4df24232009-03-05 14:34:35 -0800190 private int mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800191
Mike Lockwood9637d472009-04-02 21:41:57 -0700192 // for Settings change notification
193 private ContentQueryMap mSettings;
194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800195 /**
196 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
197 * location updates.
198 */
199 private final class Receiver implements IBinder.DeathRecipient {
200 final ILocationListener mListener;
201 final PendingIntent mPendingIntent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 final Object mKey;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400203 final HashMap<String,UpdateRecord> mUpdateRecords = new HashMap<String,UpdateRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800204
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400205 Receiver(ILocationListener listener) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 mListener = listener;
207 mPendingIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800208 mKey = listener.asBinder();
209 }
210
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400211 Receiver(PendingIntent intent) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 mPendingIntent = intent;
213 mListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800214 mKey = intent;
215 }
216
217 @Override
218 public boolean equals(Object otherObj) {
219 if (otherObj instanceof Receiver) {
220 return mKey.equals(
221 ((Receiver)otherObj).mKey);
222 }
223 return false;
224 }
225
226 @Override
227 public int hashCode() {
228 return mKey.hashCode();
229 }
230
231
232 @Override
233 public String toString() {
234 if (mListener != null) {
235 return "Receiver{"
236 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400237 + " Listener " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 } else {
239 return "Receiver{"
240 + Integer.toHexString(System.identityHashCode(this))
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400241 + " Intent " + mKey + "}";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243 }
244
245 public boolean isListener() {
246 return mListener != null;
247 }
248
249 public boolean isPendingIntent() {
250 return mPendingIntent != null;
251 }
252
253 public ILocationListener getListener() {
254 if (mListener != null) {
255 return mListener;
256 }
257 throw new IllegalStateException("Request for non-existent listener");
258 }
259
260 public PendingIntent getPendingIntent() {
261 if (mPendingIntent != null) {
262 return mPendingIntent;
263 }
264 throw new IllegalStateException("Request for non-existent intent");
265 }
266
267 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
268 if (mListener != null) {
269 try {
270 mListener.onStatusChanged(provider, status, extras);
271 } catch (RemoteException e) {
272 return false;
273 }
274 } else {
275 Intent statusChanged = new Intent();
276 statusChanged.putExtras(extras);
277 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
278 try {
279 mPendingIntent.send(mContext, 0, statusChanged, null, null);
280 } catch (PendingIntent.CanceledException e) {
281 return false;
282 }
283 }
284 return true;
285 }
286
287 public boolean callLocationChangedLocked(Location location) {
288 if (mListener != null) {
289 try {
290 mListener.onLocationChanged(location);
291 } catch (RemoteException e) {
292 return false;
293 }
294 } else {
295 Intent locationChanged = new Intent();
296 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
297 try {
298 mPendingIntent.send(mContext, 0, locationChanged, null, null);
299 } catch (PendingIntent.CanceledException e) {
300 return false;
301 }
302 }
303 return true;
304 }
305
306 public void binderDied() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700307 if (LOCAL_LOGV) {
308 Log.v(TAG, "Location listener died");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 }
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400310 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800311 removeUpdatesLocked(this);
312 }
313 }
314 }
315
Mike Lockwood9637d472009-04-02 21:41:57 -0700316 private final class SettingsObserver implements Observer {
317 public void update(Observable o, Object arg) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400318 synchronized (mLock) {
Mike Lockwood9637d472009-04-02 21:41:57 -0700319 updateProvidersLocked();
320 }
321 }
322 }
323
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 private Location readLastKnownLocationLocked(String provider) {
325 Location location = null;
326 String s = null;
327 try {
328 File f = new File(LocationManager.SYSTEM_DIR + "/location."
329 + provider);
330 if (!f.exists()) {
331 return null;
332 }
333 BufferedReader reader = new BufferedReader(new FileReader(f), 256);
334 s = reader.readLine();
335 } catch (IOException e) {
336 Log.w(TAG, "Unable to read last known location", e);
337 }
338
339 if (s == null) {
340 return null;
341 }
342 try {
343 String[] tokens = PATTERN_COMMA.split(s);
344 int idx = 0;
345 long time = Long.parseLong(tokens[idx++]);
346 double latitude = Double.parseDouble(tokens[idx++]);
347 double longitude = Double.parseDouble(tokens[idx++]);
348 double altitude = Double.parseDouble(tokens[idx++]);
349 float bearing = Float.parseFloat(tokens[idx++]);
350 float speed = Float.parseFloat(tokens[idx++]);
351
352 location = new Location(provider);
353 location.setTime(time);
354 location.setLatitude(latitude);
355 location.setLongitude(longitude);
356 location.setAltitude(altitude);
357 location.setBearing(bearing);
358 location.setSpeed(speed);
359 } catch (NumberFormatException nfe) {
360 Log.e(TAG, "NumberFormatException reading last known location", nfe);
361 return null;
362 }
363
364 return location;
365 }
366
367 private void writeLastKnownLocationLocked(String provider,
368 Location location) {
369 long now = SystemClock.elapsedRealtime();
370 Long last = mLastWriteTime.get(provider);
371 if ((last != null)
372 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
373 return;
374 }
375 mLastWriteTime.put(provider, now);
376
377 StringBuilder sb = new StringBuilder(100);
378 sb.append(location.getTime());
379 sb.append(',');
380 sb.append(location.getLatitude());
381 sb.append(',');
382 sb.append(location.getLongitude());
383 sb.append(',');
384 sb.append(location.getAltitude());
385 sb.append(',');
386 sb.append(location.getBearing());
387 sb.append(',');
388 sb.append(location.getSpeed());
389
390 FileWriter writer = null;
391 try {
392 File d = new File(LocationManager.SYSTEM_DIR);
393 if (!d.exists()) {
394 if (!d.mkdirs()) {
395 Log.w(TAG, "Unable to create directory to write location");
396 return;
397 }
398 }
399 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
400 writer = new FileWriter(f);
401 writer.write(sb.toString());
402 } catch (IOException e) {
403 Log.w(TAG, "Unable to write location", e);
404 } finally {
405 if (writer != null) {
406 try {
407 writer.close();
408 } catch (IOException e) {
409 Log.w(TAG, "Exception closing file", e);
410 }
411 }
412 }
413 }
414
415 /**
416 * Load providers from /data/location/<provider_name>/
417 * class
418 * kml
419 * nmea
420 * track
421 * location
422 * properties
423 */
424 private void loadProviders() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400425 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 if (sProvidersLoaded) {
427 return;
428 }
429
430 // Load providers
431 loadProvidersLocked();
432 sProvidersLoaded = true;
433 }
434 }
435
436 private void loadProvidersLocked() {
437 try {
438 _loadProvidersLocked();
439 } catch (Exception e) {
440 Log.e(TAG, "Exception loading providers:", e);
441 }
442 }
443
444 private void _loadProvidersLocked() {
445 // Attempt to load "real" providers first
446 if (GpsLocationProvider.isSupported()) {
447 // Create a gps location provider
Mike Lockwood4e50b782009-04-03 08:24:43 -0700448 mGpsLocationProvider = new GpsLocationProvider(mContext, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 LocationProviderImpl.addProvider(mGpsLocationProvider);
450 }
451
452 // Load fake providers if real providers are not available
453 File f = new File(LocationManager.PROVIDER_DIR);
454 if (f.isDirectory()) {
455 File[] subdirs = f.listFiles();
456 for (int i = 0; i < subdirs.length; i++) {
457 if (!subdirs[i].isDirectory()) {
458 continue;
459 }
460
461 String name = subdirs[i].getName();
462
The Android Open Source Project10592532009-03-18 17:39:46 -0700463 if (LOCAL_LOGV) {
464 Log.v(TAG, "Found dir " + subdirs[i].getAbsolutePath());
465 Log.v(TAG, "name = " + name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800466 }
467
468 // Don't create a fake provider if a real provider exists
469 if (LocationProviderImpl.getProvider(name) == null) {
470 LocationProviderImpl provider = null;
471 try {
472 File classFile = new File(subdirs[i], "class");
473 // Look for a 'class' file
474 provider = LocationProviderImpl.loadFromClass(classFile);
475
476 // Look for an 'kml', 'nmea', or 'track' file
477 if (provider == null) {
478 // Load properties from 'properties' file, if present
479 File propertiesFile = new File(subdirs[i], "properties");
480
481 if (propertiesFile.exists()) {
Mike Lockwood4e50b782009-04-03 08:24:43 -0700482 provider = new TrackProvider(name, this);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 ((TrackProvider)provider).readProperties(propertiesFile);
484
485 File kmlFile = new File(subdirs[i], "kml");
486 if (kmlFile.exists()) {
487 ((TrackProvider) provider).readKml(kmlFile);
488 } else {
489 File nmeaFile = new File(subdirs[i], "nmea");
490 if (nmeaFile.exists()) {
491 ((TrackProvider) provider).readNmea(name, nmeaFile);
492 } else {
493 File trackFile = new File(subdirs[i], "track");
494 if (trackFile.exists()) {
495 ((TrackProvider) provider).readTrack(trackFile);
496 }
497 }
498 }
499 }
500 }
501 if (provider != null) {
502 LocationProviderImpl.addProvider(provider);
503 }
504 // Grab the initial location of a TrackProvider and
505 // store it as the last known location for that provider
506 if (provider instanceof TrackProvider) {
507 TrackProvider tp = (TrackProvider) provider;
508 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation());
509 }
510 } catch (Exception e) {
511 Log.e(TAG, "Exception loading provder " + name, e);
512 }
513 }
514 }
515 }
516
517 updateProvidersLocked();
518 }
519
520 /**
521 * @param context the context that the LocationManagerService runs in
522 */
523 public LocationManagerService(Context context) {
524 super();
525 mContext = context;
526 mLocationHandler = new LocationWorkerHandler();
527
The Android Open Source Project10592532009-03-18 17:39:46 -0700528 if (LOCAL_LOGV) {
529 Log.v(TAG, "Constructed LocationManager Service");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800530 }
531
532 // Alarm manager, needs to be done before calling loadProviders() below
533 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
534
535 // Create a wake lock, needs to be done before calling loadProviders() below
536 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
537 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
538
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 // Load providers
540 loadProviders();
541
542 // Listen for Radio changes
543 mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544
545 // Register for Network (Wifi or Mobile) updates
546 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
547 IntentFilter networkIntentFilter = new IntentFilter();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800548 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
549 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
550 context.registerReceiver(networkReceiver, networkIntentFilter);
551
552 // Register for power updates
553 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
554 IntentFilter intentFilter = new IntentFilter();
555 intentFilter.addAction(ALARM_INTENT);
556 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
557 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800558 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
559 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
560 context.registerReceiver(powerStateReceiver, intentFilter);
561
Mike Lockwood9637d472009-04-02 21:41:57 -0700562 // listen for settings changes
563 ContentResolver resolver = mContext.getContentResolver();
564 Cursor settingsCursor = resolver.query(Settings.Secure.CONTENT_URI, null,
565 "(" + Settings.System.NAME + "=?)",
566 new String[]{Settings.Secure.LOCATION_PROVIDERS_ALLOWED},
567 null);
568 mSettings = new ContentQueryMap(settingsCursor, Settings.System.NAME, true, mLocationHandler);
569 SettingsObserver settingsObserver = new SettingsObserver();
570 mSettings.addObserver(settingsObserver);
571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572 // Get the wifi manager
573 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
574
575 // Create a wifi lock for future use
576 mWifiLock = getWifiWakelockLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 }
578
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700579 public void setNetworkLocationProvider(ILocationProvider provider) {
580 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
581 throw new SecurityException(
582 "Installing location providers outside of the system is not supported");
583 }
584
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400585 synchronized (mLock) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700586 mNetworkLocationProvider =
587 new LocationProviderProxy(LocationManager.NETWORK_PROVIDER, this, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 LocationProviderImpl.addProvider(mNetworkLocationProvider);
589 updateProvidersLocked();
The Android Open Source Project4df24232009-03-05 14:34:35 -0800590
591 // notify NetworkLocationProvider of any events it might have missed
Mike Lockwoodf113fbe2009-04-06 05:17:28 -0700592 mNetworkLocationProvider.updateNetworkState(mNetworkState);
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700593 mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 }
595 }
596
597 public void setLocationCollector(ILocationCollector collector) {
Mike Lockwoode932f7f2009-04-06 10:51:26 -0700598 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
599 throw new SecurityException(
600 "Installing location collectors outside of the system is not supported");
601 }
602
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400603 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 mCollector = collector;
605 if (mGpsLocationProvider != null) {
606 mGpsLocationProvider.setLocationCollector(mCollector);
607 }
608 }
609 }
610
Mike Lockwooda55c3212009-04-15 11:10:11 -0400611 public void setGeocodeProvider(IGeocodeProvider provider) {
612 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
613 throw new SecurityException(
614 "Installing location providers outside of the system is not supported");
615 }
616
617 mGeocodeProvider = provider;
618 }
619
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 private WifiManager.WifiLock getWifiWakelockLocked() {
621 if (mWifiLock == null && mWifiManager != null) {
622 mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
623 mWifiLock.setReferenceCounted(false);
624 }
625 return mWifiLock;
626 }
627
628 private boolean isAllowedBySettingsLocked(String provider) {
629 if (mEnabledProviders.contains(provider)) {
630 return true;
631 }
632 if (mDisabledProviders.contains(provider)) {
633 return false;
634 }
635 // Use system settings
636 ContentResolver resolver = mContext.getContentResolver();
637 String allowedProviders = Settings.Secure.getString(resolver,
638 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
639
640 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
641 }
642
643 private void checkPermissionsSafe(String provider) {
644 if (LocationManager.GPS_PROVIDER.equals(provider)
645 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
646 != PackageManager.PERMISSION_GRANTED)) {
647 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
648 }
649 if (LocationManager.NETWORK_PROVIDER.equals(provider)
650 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
651 != PackageManager.PERMISSION_GRANTED)
652 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
653 != PackageManager.PERMISSION_GRANTED)) {
654 throw new SecurityException(
655 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
656 }
657 }
658
659 private boolean isAllowedProviderSafe(String provider) {
660 if (LocationManager.GPS_PROVIDER.equals(provider)
661 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
662 != PackageManager.PERMISSION_GRANTED)) {
663 return false;
664 }
665 if (LocationManager.NETWORK_PROVIDER.equals(provider)
666 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
667 != PackageManager.PERMISSION_GRANTED)
668 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
669 != PackageManager.PERMISSION_GRANTED)) {
670 return false;
671 }
672
673 return true;
674 }
675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800676 public List<String> getAllProviders() {
677 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400678 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 return _getAllProvidersLocked();
680 }
681 } catch (SecurityException se) {
682 throw se;
683 } catch (Exception e) {
684 Log.e(TAG, "getAllProviders got exception:", e);
685 return null;
686 }
687 }
688
689 private List<String> _getAllProvidersLocked() {
The Android Open Source Project10592532009-03-18 17:39:46 -0700690 if (LOCAL_LOGV) {
691 Log.v(TAG, "getAllProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 }
693 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
694 ArrayList<String> out = new ArrayList<String>(providers.size());
695
696 for (LocationProviderImpl p : providers) {
697 out.add(p.getName());
698 }
699 return out;
700 }
701
702 public List<String> getProviders(boolean enabledOnly) {
703 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400704 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 return _getProvidersLocked(enabledOnly);
706 }
707 } catch (SecurityException se) {
708 throw se;
709 } catch (Exception e) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700710 Log.e(TAG, "getProviders got exception:", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800711 return null;
712 }
713 }
714
715 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700716 if (LOCAL_LOGV) {
717 Log.v(TAG, "getProviders");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800718 }
719 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
720 ArrayList<String> out = new ArrayList<String>();
721
722 for (LocationProviderImpl p : providers) {
723 String name = p.getName();
724 if (isAllowedProviderSafe(name)) {
725 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
726 continue;
727 }
728 out.add(name);
729 }
730 }
731 return out;
732 }
733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 private void updateProvidersLocked() {
735 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
736 boolean isEnabled = p.isEnabled();
737 String name = p.getName();
738 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 if (isEnabled && !shouldBeEnabled) {
741 updateProviderListenersLocked(name, false);
742 } else if (!isEnabled && shouldBeEnabled) {
743 updateProviderListenersLocked(name, true);
744 }
745
746 }
747 }
748
749 private void updateProviderListenersLocked(String provider, boolean enabled) {
750 int listeners = 0;
751
752 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
753 if (p == null) {
754 return;
755 }
756
757 ArrayList<Receiver> deadReceivers = null;
758
759 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
760 if (records != null) {
761 final int N = records.size();
762 for (int i=0; i<N; i++) {
763 UpdateRecord record = records.get(i);
764 // Sends a notification message to the receiver
765 try {
766 Receiver receiver = record.mReceiver;
767 if (receiver.isListener()) {
768 if (enabled) {
769 receiver.getListener().onProviderEnabled(provider);
770 } else {
771 receiver.getListener().onProviderDisabled(provider);
772 }
773 } else {
774 Intent providerIntent = new Intent();
775 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
776 try {
777 receiver.getPendingIntent().send(mContext, 0,
778 providerIntent, null, null);
779 } catch (PendingIntent.CanceledException e) {
780 if (deadReceivers == null) {
781 deadReceivers = new ArrayList<Receiver>();
782 deadReceivers.add(receiver);
783 }
784 }
785 }
786 } catch (RemoteException e) {
787 // The death link will clean this up.
788 }
789 listeners++;
790 }
791 }
792
793 if (deadReceivers != null) {
794 for (int i=deadReceivers.size()-1; i>=0; i--) {
795 removeUpdatesLocked(deadReceivers.get(i));
796 }
797 }
798
799 if (enabled) {
800 p.enable();
801 if (listeners > 0) {
802 p.setMinTime(getMinTimeLocked(provider));
803 p.enableLocationTracking(true);
804 updateWakelockStatusLocked(mScreenOn);
805 }
806 } else {
807 p.enableLocationTracking(false);
808 if (p == mGpsLocationProvider) {
809 mGpsNavigating = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800810 }
811 p.disable();
812 updateWakelockStatusLocked(mScreenOn);
813 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 }
815
816 private long getMinTimeLocked(String provider) {
817 long minTime = Long.MAX_VALUE;
818 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
819 if (records != null) {
820 for (int i=records.size()-1; i>=0; i--) {
821 minTime = Math.min(minTime, records.get(i).mMinTime);
822 }
823 }
824 return minTime;
825 }
826
827 private class UpdateRecord {
828 final String mProvider;
829 final Receiver mReceiver;
830 final long mMinTime;
831 final float mMinDistance;
832 final int mUid;
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400833 Location mLastFixBroadcast;
834 long mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835
836 /**
837 * Note: must be constructed with lock held.
838 */
839 UpdateRecord(String provider, long minTime, float minDistance,
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400840 Receiver receiver, int uid) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800841 mProvider = provider;
842 mReceiver = receiver;
843 mMinTime = minTime;
844 mMinDistance = minDistance;
845 mUid = uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800846
847 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
848 if (records == null) {
849 records = new ArrayList<UpdateRecord>();
850 mRecordsByProvider.put(provider, records);
851 }
852 if (!records.contains(this)) {
853 records.add(this);
854 }
855 }
856
857 /**
858 * Method to be called when a record will no longer be used. Calling this multiple times
859 * must have the same effect as calling it once.
860 */
861 void disposeLocked() {
862 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
863 records.remove(this);
864 }
865
866 @Override
867 public String toString() {
868 return "UpdateRecord{"
869 + Integer.toHexString(System.identityHashCode(this))
870 + " " + mProvider + " " + mReceiver + "}";
871 }
872
873 void dump(PrintWriter pw, String prefix) {
874 pw.println(prefix + this);
875 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
876 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400877 pw.println(prefix + "mUid=" + mUid);
878 pw.println(prefix + "mLastFixBroadcast:");
879 mLastFixBroadcast.dump(new PrintWriterPrinter(pw), prefix + " ");
880 pw.println(prefix + "mLastStatusBroadcast=" + mLastStatusBroadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 }
882
883 /**
884 * Calls dispose().
885 */
886 @Override protected void finalize() {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400887 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800888 disposeLocked();
889 }
890 }
891 }
892
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400893 private Receiver getReceiver(ILocationListener listener) {
894 IBinder binder = listener.asBinder();
895 Receiver receiver = mReceivers.get(binder);
896 if (receiver == null) {
897 receiver = new Receiver(listener);
898 mReceivers.put(binder, receiver);
899
900 try {
901 if (receiver.isListener()) {
902 receiver.getListener().asBinder().linkToDeath(receiver, 0);
903 }
904 } catch (RemoteException e) {
905 Log.e(TAG, "linkToDeath failed:", e);
906 return null;
907 }
908 }
909 return receiver;
910 }
911
912 private Receiver getReceiver(PendingIntent intent) {
913 Receiver receiver = mReceivers.get(intent);
914 if (receiver == null) {
915 receiver = new Receiver(intent);
916 mReceivers.put(intent, receiver);
917 }
918 return receiver;
919 }
920
921 private boolean providerHasListener(String provider, int uid, Receiver excludedReceiver) {
922 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
923 if (records != null) {
924 for (int i = records.size() - 1; i >= 0; i--) {
925 UpdateRecord record = records.get(i);
926 if (record.mUid == uid && record.mReceiver != excludedReceiver) {
927 return true;
928 }
929 }
930 }
931 if (LocationManager.GPS_PROVIDER.equals(provider) ||
932 LocationManager.NETWORK_PROVIDER.equals(provider)) {
933 for (ProximityAlert alert : mProximityAlerts.values()) {
934 if (alert.mUid == uid) {
935 return true;
936 }
937 }
938 }
939 return false;
940 }
941
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800942 public void requestLocationUpdates(String provider,
943 long minTime, float minDistance, ILocationListener listener) {
944
945 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400946 synchronized (mLock) {
947 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800948 }
949 } catch (SecurityException se) {
950 throw se;
951 } catch (Exception e) {
952 Log.e(TAG, "requestUpdates got exception:", e);
953 }
954 }
955
956 public void requestLocationUpdatesPI(String provider,
957 long minTime, float minDistance, PendingIntent intent) {
958 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400959 synchronized (mLock) {
960 requestLocationUpdatesLocked(provider, minTime, minDistance, getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800961 }
962 } catch (SecurityException se) {
963 throw se;
964 } catch (Exception e) {
965 Log.e(TAG, "requestUpdates got exception:", e);
966 }
967 }
968
969 private void requestLocationUpdatesLocked(String provider,
970 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700971 if (LOCAL_LOGV) {
972 Log.v(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 }
974
975 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
976 if (impl == null) {
977 throw new IllegalArgumentException("provider=" + provider);
978 }
979
980 checkPermissionsSafe(provider);
981
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 // so wakelock calls will succeed
983 final int callingUid = Binder.getCallingUid();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400984 boolean newUid = !providerHasListener(provider, callingUid, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800985 long identity = Binder.clearCallingIdentity();
986 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400987 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance, receiver, callingUid);
988 UpdateRecord oldRecord = receiver.mUpdateRecords.put(provider, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 if (oldRecord != null) {
990 oldRecord.disposeLocked();
991 }
992
Mike Lockwood2f82c4e2009-04-17 08:24:10 -0400993 if (newUid) {
994 impl.addListener(callingUid);
995 }
996
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800997 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
998 if (isProviderEnabled) {
999 long minTimeForProvider = getMinTimeLocked(provider);
1000 impl.setMinTime(minTimeForProvider);
1001 impl.enableLocationTracking(true);
1002 updateWakelockStatusLocked(mScreenOn);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 } else {
1004 try {
1005 // Notify the listener that updates are currently disabled
1006 if (receiver.isListener()) {
1007 receiver.getListener().onProviderDisabled(provider);
1008 }
1009 } catch(RemoteException e) {
1010 Log.w(TAG, "RemoteException calling onProviderDisabled on " +
1011 receiver.getListener());
1012 }
1013 }
1014 } finally {
1015 Binder.restoreCallingIdentity(identity);
1016 }
1017 }
1018
1019 public void removeUpdates(ILocationListener listener) {
1020 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001021 synchronized (mLock) {
1022 removeUpdatesLocked(getReceiver(listener));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024 } catch (SecurityException se) {
1025 throw se;
1026 } catch (Exception e) {
1027 Log.e(TAG, "removeUpdates got exception:", e);
1028 }
1029 }
1030
1031 public void removeUpdatesPI(PendingIntent intent) {
1032 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001033 synchronized (mLock) {
1034 removeUpdatesLocked(getReceiver(intent));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001035 }
1036 } catch (SecurityException se) {
1037 throw se;
1038 } catch (Exception e) {
1039 Log.e(TAG, "removeUpdates got exception:", e);
1040 }
1041 }
1042
1043 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001044 if (LOCAL_LOGV) {
1045 Log.v(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 }
1047
1048 // so wakelock calls will succeed
1049 final int callingUid = Binder.getCallingUid();
1050 long identity = Binder.clearCallingIdentity();
1051 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001052 if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
1053 receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 }
1055
1056 // Record which providers were associated with this listener
1057 HashSet<String> providers = new HashSet<String>();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001058 HashMap<String,UpdateRecord> oldRecords = receiver.mUpdateRecords;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001059 if (oldRecords != null) {
1060 // Call dispose() on the obsolete update records.
1061 for (UpdateRecord record : oldRecords.values()) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001062 if (!providerHasListener(record.mProvider, callingUid, receiver)) {
1063 LocationProviderImpl impl =
1064 LocationProviderImpl.getProvider(record.mProvider);
1065 if (impl != null) {
1066 impl.removeListener(callingUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 }
1068 }
1069 record.disposeLocked();
1070 }
1071 // Accumulate providers
1072 providers.addAll(oldRecords.keySet());
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074
1075 // See if the providers associated with this listener have any
1076 // other listeners; if one does, inform it of the new smallest minTime
1077 // value; if one does not, disable location tracking for it
1078 for (String provider : providers) {
1079 // If provider is already disabled, don't need to do anything
1080 if (!isAllowedBySettingsLocked(provider)) {
1081 continue;
1082 }
1083
1084 boolean hasOtherListener = false;
1085 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1086 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1087 hasOtherListener = true;
1088 }
1089
1090 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1091 if (p != null) {
1092 if (hasOtherListener) {
1093 p.setMinTime(getMinTimeLocked(provider));
1094 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001095 p.enableLocationTracking(false);
1096 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097 }
1098 }
1099
1100 updateWakelockStatusLocked(mScreenOn);
1101 } finally {
1102 Binder.restoreCallingIdentity(identity);
1103 }
1104 }
1105
1106 public boolean addGpsStatusListener(IGpsStatusListener listener) {
1107 if (mGpsLocationProvider == null) {
1108 return false;
1109 }
1110 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
1111 PackageManager.PERMISSION_GRANTED) {
1112 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1113 }
1114
1115 try {
1116 mGpsLocationProvider.addGpsStatusListener(listener);
1117 } catch (RemoteException e) {
1118 Log.w(TAG, "RemoteException in addGpsStatusListener");
1119 return false;
1120 }
1121 return true;
1122 }
1123
1124 public void removeGpsStatusListener(IGpsStatusListener listener) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001125 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001126 mGpsLocationProvider.removeGpsStatusListener(listener);
1127 }
1128 }
1129
1130 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1131 // first check for permission to the provider
1132 checkPermissionsSafe(provider);
1133 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1134 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1135 != PackageManager.PERMISSION_GRANTED)) {
1136 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1137 }
1138
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001139 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001140 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1141 if (provider == null) {
1142 return false;
1143 }
1144
1145 return impl.sendExtraCommand(command, extras);
1146 }
1147 }
1148
1149 class ProximityAlert {
1150 final int mUid;
1151 final double mLatitude;
1152 final double mLongitude;
1153 final float mRadius;
1154 final long mExpiration;
1155 final PendingIntent mIntent;
1156 final Location mLocation;
1157
1158 public ProximityAlert(int uid, double latitude, double longitude,
1159 float radius, long expiration, PendingIntent intent) {
1160 mUid = uid;
1161 mLatitude = latitude;
1162 mLongitude = longitude;
1163 mRadius = radius;
1164 mExpiration = expiration;
1165 mIntent = intent;
1166
1167 mLocation = new Location("");
1168 mLocation.setLatitude(latitude);
1169 mLocation.setLongitude(longitude);
1170 }
1171
1172 long getExpiration() {
1173 return mExpiration;
1174 }
1175
1176 PendingIntent getIntent() {
1177 return mIntent;
1178 }
1179
1180 boolean isInProximity(double latitude, double longitude) {
1181 Location loc = new Location("");
1182 loc.setLatitude(latitude);
1183 loc.setLongitude(longitude);
1184
1185 double radius = loc.distanceTo(mLocation);
1186 return radius <= mRadius;
1187 }
1188
1189 @Override
1190 public String toString() {
1191 return "ProximityAlert{"
1192 + Integer.toHexString(System.identityHashCode(this))
1193 + " uid " + mUid + mIntent + "}";
1194 }
1195
1196 void dump(PrintWriter pw, String prefix) {
1197 pw.println(prefix + this);
1198 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1199 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1200 pw.println(prefix + "mIntent=" + mIntent);
1201 pw.println(prefix + "mLocation:");
1202 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1203 }
1204 }
1205
1206 // Listener for receiving locations to trigger proximity alerts
1207 class ProximityListener extends ILocationListener.Stub {
1208
1209 boolean isGpsAvailable = false;
1210
1211 // Note: this is called with the lock held.
1212 public void onLocationChanged(Location loc) {
1213
1214 // If Gps is available, then ignore updates from NetworkLocationProvider
1215 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1216 isGpsAvailable = true;
1217 }
1218 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1219 return;
1220 }
1221
1222 // Process proximity alerts
1223 long now = System.currentTimeMillis();
1224 double latitude = loc.getLatitude();
1225 double longitude = loc.getLongitude();
1226 ArrayList<PendingIntent> intentsToRemove = null;
1227
1228 for (ProximityAlert alert : mProximityAlerts.values()) {
1229 PendingIntent intent = alert.getIntent();
1230 long expiration = alert.getExpiration();
1231
1232 if ((expiration == -1) || (now <= expiration)) {
1233 boolean entered = mProximitiesEntered.contains(alert);
1234 boolean inProximity =
1235 alert.isInProximity(latitude, longitude);
1236 if (!entered && inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001237 if (LOCAL_LOGV) {
1238 Log.v(TAG, "Entered alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 }
1240 mProximitiesEntered.add(alert);
1241 Intent enteredIntent = new Intent();
1242 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1243 try {
1244 intent.send(mContext, 0, enteredIntent, null, null);
1245 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001246 if (LOCAL_LOGV) {
1247 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001248 }
1249 if (intentsToRemove == null) {
1250 intentsToRemove = new ArrayList<PendingIntent>();
1251 }
1252 intentsToRemove.add(intent);
1253 }
1254 } else if (entered && !inProximity) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001255 if (LOCAL_LOGV) {
1256 Log.v(TAG, "Exited alert");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001257 }
1258 mProximitiesEntered.remove(alert);
1259 Intent exitedIntent = new Intent();
1260 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1261 try {
1262 intent.send(mContext, 0, exitedIntent, null, null);
1263 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001264 if (LOCAL_LOGV) {
1265 Log.v(TAG, "Canceled proximity alert: " + alert, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001266 }
1267 if (intentsToRemove == null) {
1268 intentsToRemove = new ArrayList<PendingIntent>();
1269 }
1270 intentsToRemove.add(intent);
1271 }
1272 }
1273 } else {
1274 // Mark alert for expiration
The Android Open Source Project10592532009-03-18 17:39:46 -07001275 if (LOCAL_LOGV) {
1276 Log.v(TAG, "Expiring proximity alert: " + alert);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001277 }
1278 if (intentsToRemove == null) {
1279 intentsToRemove = new ArrayList<PendingIntent>();
1280 }
1281 intentsToRemove.add(alert.getIntent());
1282 }
1283 }
1284
1285 // Remove expired alerts
1286 if (intentsToRemove != null) {
1287 for (PendingIntent i : intentsToRemove) {
1288 mProximityAlerts.remove(i);
1289 ProximityAlert alert = mProximityAlerts.get(i);
1290 mProximitiesEntered.remove(alert);
1291 }
1292 }
1293
1294 }
1295
1296 // Note: this is called with the lock held.
1297 public void onProviderDisabled(String provider) {
1298 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1299 isGpsAvailable = false;
1300 }
1301 }
1302
1303 // Note: this is called with the lock held.
1304 public void onProviderEnabled(String provider) {
1305 // ignore
1306 }
1307
1308 // Note: this is called with the lock held.
1309 public void onStatusChanged(String provider, int status, Bundle extras) {
1310 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1311 (status != LocationProvider.AVAILABLE)) {
1312 isGpsAvailable = false;
1313 }
1314 }
1315 }
1316
1317 public void addProximityAlert(double latitude, double longitude,
1318 float radius, long expiration, PendingIntent intent) {
1319 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001320 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001321 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1322 }
1323 } catch (SecurityException se) {
1324 throw se;
1325 } catch (Exception e) {
1326 Log.e(TAG, "addProximityAlert got exception:", e);
1327 }
1328 }
1329
1330 private void addProximityAlertLocked(double latitude, double longitude,
1331 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001332 if (LOCAL_LOGV) {
1333 Log.v(TAG, "addProximityAlert: latitude = " + latitude +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 ", longitude = " + longitude +
1335 ", expiration = " + expiration +
1336 ", intent = " + intent);
1337 }
1338
1339 // Require ability to access all providers for now
1340 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1341 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
1342 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1343 }
1344
1345 if (expiration != -1) {
1346 expiration += System.currentTimeMillis();
1347 }
1348 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1349 latitude, longitude, radius, expiration, intent);
1350 mProximityAlerts.put(intent, alert);
1351
1352 if (mProximityListener == null) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001353 mProximityListener = new Receiver(new ProximityListener());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354
1355 LocationProvider provider = LocationProviderImpl.getProvider(
1356 LocationManager.GPS_PROVIDER);
1357 if (provider != null) {
1358 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
1359 }
1360
1361 provider =
1362 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
1363 if (provider != null) {
1364 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
1365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001366 }
1367 }
1368
1369 public void removeProximityAlert(PendingIntent intent) {
1370 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001371 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 removeProximityAlertLocked(intent);
1373 }
1374 } catch (SecurityException se) {
1375 throw se;
1376 } catch (Exception e) {
1377 Log.e(TAG, "removeProximityAlert got exception:", e);
1378 }
1379 }
1380
1381 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project10592532009-03-18 17:39:46 -07001382 if (LOCAL_LOGV) {
1383 Log.v(TAG, "removeProximityAlert: intent = " + intent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001384 }
1385
1386 mProximityAlerts.remove(intent);
1387 if (mProximityAlerts.size() == 0) {
1388 removeUpdatesLocked(mProximityListener);
1389 mProximityListener = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001390 }
1391 }
1392
1393 /**
1394 * @return null if the provider does not exits
1395 * @throw SecurityException if the provider is not allowed to be
1396 * accessed by the caller
1397 */
1398 public Bundle getProviderInfo(String provider) {
1399 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001400 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001401 return _getProviderInfoLocked(provider);
1402 }
1403 } catch (SecurityException se) {
1404 throw se;
1405 } catch (Exception e) {
1406 Log.e(TAG, "_getProviderInfo got exception:", e);
1407 return null;
1408 }
1409 }
1410
1411 private Bundle _getProviderInfoLocked(String provider) {
1412 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1413 if (p == null) {
1414 return null;
1415 }
1416
1417 checkPermissionsSafe(provider);
1418
1419 Bundle b = new Bundle();
1420 b.putBoolean("network", p.requiresNetwork());
1421 b.putBoolean("satellite", p.requiresSatellite());
1422 b.putBoolean("cell", p.requiresCell());
1423 b.putBoolean("cost", p.hasMonetaryCost());
1424 b.putBoolean("altitude", p.supportsAltitude());
1425 b.putBoolean("speed", p.supportsSpeed());
1426 b.putBoolean("bearing", p.supportsBearing());
1427 b.putInt("power", p.getPowerRequirement());
1428 b.putInt("accuracy", p.getAccuracy());
1429
1430 return b;
1431 }
1432
1433 public boolean isProviderEnabled(String provider) {
1434 try {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001435 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 return _isProviderEnabledLocked(provider);
1437 }
1438 } catch (SecurityException se) {
1439 throw se;
1440 } catch (Exception e) {
1441 Log.e(TAG, "isProviderEnabled got exception:", e);
1442 return false;
1443 }
1444 }
1445
Mike Lockwood4e50b782009-04-03 08:24:43 -07001446 public void setLocation(Location location) {
1447 mLocationHandler.removeMessages(MESSAGE_LOCATION_CHANGED, location);
1448 Message m = Message.obtain(mLocationHandler, MESSAGE_LOCATION_CHANGED, location);
1449 mLocationHandler.sendMessageAtFrontOfQueue(m);
1450 }
1451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 private boolean _isProviderEnabledLocked(String provider) {
1453 checkPermissionsSafe(provider);
1454
1455 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1456 if (p == null) {
1457 throw new IllegalArgumentException("provider=" + provider);
1458 }
1459 return isAllowedBySettingsLocked(provider);
1460 }
1461
1462 public Location getLastKnownLocation(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 _getLastKnownLocationLocked(provider);
1466 }
1467 } catch (SecurityException se) {
1468 throw se;
1469 } catch (Exception e) {
1470 Log.e(TAG, "getLastKnownLocation got exception:", e);
1471 return null;
1472 }
1473 }
1474
1475 private Location _getLastKnownLocationLocked(String provider) {
1476 checkPermissionsSafe(provider);
1477
1478 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1479 if (p == null) {
1480 throw new IllegalArgumentException("provider=" + provider);
1481 }
1482
1483 if (!isAllowedBySettingsLocked(provider)) {
1484 return null;
1485 }
1486
1487 Location location = mLastKnownLocation.get(provider);
1488 if (location == null) {
1489 // Get the persistent last known location for the provider
1490 location = readLastKnownLocationLocked(provider);
1491 if (location != null) {
1492 mLastKnownLocation.put(provider, location);
1493 }
1494 }
1495
1496 return location;
1497 }
1498
1499 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
1500 // Always broadcast the first update
1501 if (lastLoc == null) {
1502 return true;
1503 }
1504
1505 // Don't broadcast same location again regardless of condition
1506 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1507 if (loc.getTime() == lastLoc.getTime()) {
1508 return false;
1509 }
1510
1511 // Check whether sufficient distance has been traveled
1512 double minDistance = record.mMinDistance;
1513 if (minDistance > 0.0) {
1514 if (loc.distanceTo(lastLoc) <= minDistance) {
1515 return false;
1516 }
1517 }
1518
1519 return true;
1520 }
1521
Mike Lockwood4e50b782009-04-03 08:24:43 -07001522 private void handleLocationChangedLocked(Location location) {
1523 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001524 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
1525 if (records == null || records.size() == 0) {
1526 return;
1527 }
1528
1529 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1530 if (p == null) {
1531 return;
1532 }
1533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001534 // Update last known location for provider
Mike Lockwood4e50b782009-04-03 08:24:43 -07001535 Location lastLocation = mLastKnownLocation.get(provider);
1536 if (lastLocation == null) {
1537 mLastKnownLocation.put(provider, new Location(location));
1538 } else {
1539 lastLocation.set(location);
1540 }
1541 writeLastKnownLocationLocked(provider, location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001542
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001543 if (LocationManager.NETWORK_PROVIDER.equals(p.getName())) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001544 mWakeLockNetworkReceived = true;
1545 } else if (p instanceof GpsLocationProvider) {
1546 // Gps location received signal is in NetworkStateBroadcastReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 }
1548
1549 // Fetch latest status update time
1550 long newStatusUpdateTime = p.getStatusUpdateTime();
1551
Mike Lockwood7ec434e2009-03-27 07:46:48 -07001552 // Get latest status
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001553 Bundle extras = new Bundle();
1554 int status = p.getStatus(extras);
1555
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001556 ArrayList<Receiver> deadReceivers = null;
1557
1558 // Broadcast location or status to all listeners
1559 final int N = records.size();
1560 for (int i=0; i<N; i++) {
1561 UpdateRecord r = records.get(i);
1562 Receiver receiver = r.mReceiver;
1563
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001564 Location lastLoc = r.mLastFixBroadcast;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001565 if ((lastLoc == null) || shouldBroadcastSafe(location, lastLoc, r)) {
1566 if (lastLoc == null) {
1567 lastLoc = new Location(location);
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001568 r.mLastFixBroadcast = lastLoc;
Mike Lockwood4e50b782009-04-03 08:24:43 -07001569 } else {
1570 lastLoc.set(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001572 if (!receiver.callLocationChangedLocked(location)) {
1573 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
1574 if (deadReceivers == null) {
1575 deadReceivers = new ArrayList<Receiver>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001576 }
Mike Lockwood4e50b782009-04-03 08:24:43 -07001577 deadReceivers.add(receiver);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 }
1579 }
1580
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001581 long prevStatusUpdateTime = r.mLastStatusBroadcast;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001582 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1583 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1584
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001585 r.mLastStatusBroadcast = newStatusUpdateTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001586 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
1587 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
1588 if (deadReceivers == null) {
1589 deadReceivers = new ArrayList<Receiver>();
1590 }
1591 if (!deadReceivers.contains(receiver)) {
1592 deadReceivers.add(receiver);
1593 }
1594 }
1595 }
1596 }
1597
1598 if (deadReceivers != null) {
1599 for (int i=deadReceivers.size()-1; i>=0; i--) {
1600 removeUpdatesLocked(deadReceivers.get(i));
1601 }
1602 }
1603 }
1604
1605 private class LocationWorkerHandler extends Handler {
1606
1607 @Override
1608 public void handleMessage(Message msg) {
1609 try {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001610 if (msg.what == MESSAGE_LOCATION_CHANGED) {
1611 // log("LocationWorkerHandler: MESSAGE_LOCATION_CHANGED!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001613 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001614 Location location = (Location) msg.obj;
1615 String provider = location.getProvider();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001616 if (!isAllowedBySettingsLocked(provider)) {
1617 return;
1618 }
1619
1620 // Process the location fix if the screen is on or we're holding a wakelock
1621 if (mScreenOn || (mWakeLockAcquireTime != 0)) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07001622 handleLocationChangedLocked(location);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001623 }
1624
1625 if ((mWakeLockAcquireTime != 0) &&
1626 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
1627 > MAX_TIME_FOR_WAKE_LOCK)) {
1628
1629 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1630 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1631
1632 log("LocationWorkerHandler: Exceeded max time for wake lock");
1633 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1634 sendMessageAtFrontOfQueue(m);
1635
1636 } else if (mWakeLockAcquireTime != 0 &&
1637 mWakeLockGpsReceived && mWakeLockNetworkReceived) {
1638
1639 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1640 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1641
1642 log("LocationWorkerHandler: Locations received.");
1643 mWakeLockAcquireTime = 0;
1644 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1645 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
1646 }
1647 }
1648
1649 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) {
1650 log("LocationWorkerHandler: Acquire");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001651 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 acquireWakeLockLocked();
1653 }
1654 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
1655 log("LocationWorkerHandler: Release");
1656
1657 // Update wakelock status so the next alarm is set before releasing wakelock
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001658 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 updateWakelockStatusLocked(mScreenOn);
1660 releaseWakeLockLocked();
1661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001662 }
1663 } catch (Exception e) {
1664 // Log, don't crash!
1665 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1666 }
1667 }
1668 }
1669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001670 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1671 @Override public void onReceive(Context context, Intent intent) {
1672 String action = intent.getAction();
1673
1674 if (action.equals(ALARM_INTENT)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001675 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001676 log("PowerStateBroadcastReceiver: Alarm received");
1677 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1678 // Have to do this immediately, rather than posting a
1679 // message, so we execute our code while the system
1680 // is holding a wake lock until the alarm broadcast
1681 // is finished.
1682 acquireWakeLockLocked();
1683 }
1684
1685 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1686 log("PowerStateBroadcastReceiver: Screen off");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001687 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001688 updateWakelockStatusLocked(false);
1689 }
1690
1691 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1692 log("PowerStateBroadcastReceiver: Screen on");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001693 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 updateWakelockStatusLocked(true);
1695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001696 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1697 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001698 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1700 if (uid >= 0) {
1701 ArrayList<Receiver> removedRecs = null;
1702 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1703 for (int j=i.size()-1; j>=0; j--) {
1704 UpdateRecord ur = i.get(j);
1705 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1706 if (removedRecs == null) {
1707 removedRecs = new ArrayList<Receiver>();
1708 }
1709 if (!removedRecs.contains(ur.mReceiver)) {
1710 removedRecs.add(ur.mReceiver);
1711 }
1712 }
1713 }
1714 }
1715 ArrayList<ProximityAlert> removedAlerts = null;
1716 for (ProximityAlert i : mProximityAlerts.values()) {
1717 if (i.mUid == uid) {
1718 if (removedAlerts == null) {
1719 removedAlerts = new ArrayList<ProximityAlert>();
1720 }
1721 if (!removedAlerts.contains(i)) {
1722 removedAlerts.add(i);
1723 }
1724 }
1725 }
1726 if (removedRecs != null) {
1727 for (int i=removedRecs.size()-1; i>=0; i--) {
1728 removeUpdatesLocked(removedRecs.get(i));
1729 }
1730 }
1731 if (removedAlerts != null) {
1732 for (int i=removedAlerts.size()-1; i>=0; i--) {
1733 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1734 }
1735 }
1736 }
1737 }
1738 }
1739 }
1740 }
1741
1742 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1743 @Override public void onReceive(Context context, Intent intent) {
1744 String action = intent.getAction();
1745
Mike Lockwoodf113fbe2009-04-06 05:17:28 -07001746 if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001747 boolean noConnectivity =
1748 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1749 if (!noConnectivity) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001750 mNetworkState = LocationProvider.AVAILABLE;
1751 } else {
1752 mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 }
1754
1755 // Notify location providers of current network state
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001756 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1758 for (LocationProviderImpl provider : providers) {
1759 if (provider.requiresNetwork()) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08001760 provider.updateNetworkState(mNetworkState);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 }
1762 }
1763 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001764 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
1765
1766 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
1767 false);
1768
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04001769 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001770 if (enabled) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001771 mGpsNavigating = true;
1772 } else {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001773 mGpsNavigating = false;
1774 // When GPS is disabled, we are OK to release wake-lock
1775 mWakeLockGpsReceived = true;
1776 }
1777 }
1778 }
1779
1780 }
1781 }
1782
1783 // Wake locks
1784
1785 private void updateWakelockStatusLocked(boolean screenOn) {
1786 log("updateWakelockStatus(): " + screenOn);
1787
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001788 long callerId = Binder.clearCallingIdentity();
1789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 boolean needsLock = false;
1791 long minTime = Integer.MAX_VALUE;
1792
1793 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
1794 needsLock = true;
1795 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
1796 }
1797
1798 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
1799 needsLock = true;
1800 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
1801 if (screenOn) {
1802 startGpsLocked();
1803 } else if (mScreenOn && !screenOn) {
1804 // We just turned the screen off so stop navigating
1805 stopGpsLocked();
1806 }
1807 }
1808
1809 mScreenOn = screenOn;
1810
1811 PendingIntent sender =
1812 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
1813
1814 // Cancel existing alarm
1815 log("Cancelling existing alarm");
1816 mAlarmManager.cancel(sender);
1817
1818 if (needsLock && !mScreenOn) {
1819 long now = SystemClock.elapsedRealtime();
1820 mAlarmManager.set(
1821 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
1822 mAlarmInterval = minTime;
1823 log("Creating a new wakelock alarm with minTime = " + minTime);
1824 } else {
1825 log("No need for alarm");
1826 mAlarmInterval = -1;
1827
1828 // Clear out existing wakelocks
1829 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1830 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1831 releaseWakeLockLocked();
1832 }
Amith Yamasanie1ccba22009-04-02 11:40:25 -07001833 Binder.restoreCallingIdentity(callerId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001834 }
1835
1836 private void acquireWakeLockLocked() {
1837 try {
1838 acquireWakeLockXLocked();
1839 } catch (Exception e) {
1840 // This is to catch a runtime exception thrown when we try to release an
1841 // already released lock.
1842 Log.e(TAG, "exception in acquireWakeLock()", e);
1843 }
1844 }
1845
1846 private void acquireWakeLockXLocked() {
1847 if (mWakeLock.isHeld()) {
1848 log("Must release wakelock before acquiring");
1849 mWakeLockAcquireTime = 0;
1850 mWakeLock.release();
1851 }
1852
1853 boolean networkActive = (mNetworkLocationProvider != null)
1854 && mNetworkLocationProvider.isLocationTracking();
1855 boolean gpsActive = (mGpsLocationProvider != null)
1856 && mGpsLocationProvider.isLocationTracking();
1857
1858 boolean needsLock = networkActive || gpsActive;
1859 if (!needsLock) {
1860 log("No need for Lock!");
1861 return;
1862 }
1863
1864 mWakeLockGpsReceived = !gpsActive;
1865 mWakeLockNetworkReceived = !networkActive;
1866
1867 // Acquire wake lock
1868 mWakeLock.acquire();
1869 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
1870 log("Acquired wakelock");
1871
1872 // Start the gps provider
1873 startGpsLocked();
1874
1875 // Acquire cell lock
1876 if (mCellWakeLockAcquired) {
1877 // Lock is already acquired
1878 } else if (!mWakeLockNetworkReceived) {
1879 mTelephonyManager.enableLocationUpdates();
1880 mCellWakeLockAcquired = true;
1881 } else {
1882 mCellWakeLockAcquired = false;
1883 }
1884
1885 // Notify NetworkLocationProvider
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001886 if (mNetworkLocationProvider != null) {
1887 mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
1890 // Acquire wifi lock
1891 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
1892 if (wifiLock != null) {
1893 if (mWifiWakeLockAcquired) {
1894 // Lock is already acquired
1895 } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) {
1896 wifiLock.acquire();
1897 mWifiWakeLockAcquired = true;
1898 } else {
1899 mWifiWakeLockAcquired = false;
1900 Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock");
1901 }
1902 }
1903 }
1904
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001905 private void startGpsLocked() {
1906 boolean gpsActive = (mGpsLocationProvider != null)
1907 && mGpsLocationProvider.isLocationTracking();
1908 if (gpsActive) {
1909 mGpsLocationProvider.startNavigating();
1910 }
1911 }
1912
1913 private void stopGpsLocked() {
1914 boolean gpsActive = mGpsLocationProvider != null
1915 && mGpsLocationProvider.isLocationTracking();
1916 if (gpsActive) {
1917 mGpsLocationProvider.stopNavigating();
1918 }
1919 }
1920
1921 private void releaseWakeLockLocked() {
1922 try {
1923 releaseWakeLockXLocked();
1924 } catch (Exception e) {
1925 // This is to catch a runtime exception thrown when we try to release an
1926 // already released lock.
1927 Log.e(TAG, "exception in releaseWakeLock()", e);
1928 }
1929 }
1930
1931 private void releaseWakeLockXLocked() {
1932 // Release wifi lock
1933 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
1934 if (wifiLock != null) {
1935 if (mWifiWakeLockAcquired) {
1936 wifiLock.release();
1937 mWifiWakeLockAcquired = false;
1938 }
1939 }
1940
1941 if (!mScreenOn) {
1942 // Stop the gps
1943 stopGpsLocked();
1944 }
1945
1946 // Release cell lock
1947 if (mCellWakeLockAcquired) {
1948 mTelephonyManager.disableLocationUpdates();
1949 mCellWakeLockAcquired = false;
1950 }
1951
1952 // Notify NetworkLocationProvider
Mike Lockwoode932f7f2009-04-06 10:51:26 -07001953 if (mNetworkLocationProvider != null) {
1954 mNetworkLocationProvider.updateCellLockStatus(mCellWakeLockAcquired);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001955 }
1956
1957 // Release wake lock
1958 mWakeLockAcquireTime = 0;
1959 if (mWakeLock.isHeld()) {
1960 log("Released wakelock");
1961 mWakeLock.release();
1962 } else {
1963 log("Can't release wakelock again!");
1964 }
1965 }
1966
1967 // Geocoder
1968
1969 public String getFromLocation(double latitude, double longitude, int maxResults,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001970 String language, String country, String variant, String appName, List<Address> addrs) {
1971 if (mGeocodeProvider != null) {
1972 try {
1973 return mGeocodeProvider.getFromLocation(latitude, longitude, maxResults, language, country,
1974 variant, appName, addrs);
1975 } catch (RemoteException e) {
1976 Log.e(TAG, "getFromLocation failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001977 }
1978 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001979 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001980 }
1981
Mike Lockwooda55c3212009-04-15 11:10:11 -04001982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001983 public String getFromLocationName(String locationName,
Mike Lockwooda55c3212009-04-15 11:10:11 -04001984 double lowerLeftLatitude, double lowerLeftLongitude,
1985 double upperRightLatitude, double upperRightLongitude, int maxResults,
1986 String language, String country, String variant, String appName, List<Address> addrs) {
1987
1988 if (mGeocodeProvider != null) {
1989 try {
1990 return mGeocodeProvider.getFromLocationName(locationName, lowerLeftLatitude,
1991 lowerLeftLongitude, upperRightLatitude, upperRightLongitude,
1992 maxResults, language, country, variant, appName, addrs);
1993 } catch (RemoteException e) {
1994 Log.e(TAG, "getFromLocationName failed", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001995 }
1996 }
Mike Lockwooda55c3212009-04-15 11:10:11 -04001997 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001998 }
1999
2000 // Mock Providers
2001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002002 private void checkMockPermissionsSafe() {
2003 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2004 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
2005 if (!allowMocks) {
2006 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2007 }
2008
2009 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2010 PackageManager.PERMISSION_GRANTED) {
2011 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2012 }
2013 }
2014
2015 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
2016 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
2017 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
2018 checkMockPermissionsSafe();
2019
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002020 synchronized (mLock) {
Mike Lockwood4e50b782009-04-03 08:24:43 -07002021 MockProvider provider = new MockProvider(name, this,
2022 requiresNetwork, requiresSatellite,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002023 requiresCell, hasMonetaryCost, supportsAltitude,
2024 supportsSpeed, supportsBearing, powerRequirement, accuracy);
2025 if (LocationProviderImpl.getProvider(name) != null) {
2026 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2027 }
2028 LocationProviderImpl.addProvider(provider);
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002029 mMockProviders.put(name, provider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002030 updateProvidersLocked();
2031 }
2032 }
2033
2034 public void removeTestProvider(String provider) {
2035 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002036 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002037 MockProvider mockProvider = mMockProviders.get(provider);
2038 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002039 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2040 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002041 LocationProviderImpl.removeProvider(mockProvider);
2042 mMockProviders.remove(mockProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002043 updateProvidersLocked();
2044 }
2045 }
2046
2047 public void setTestProviderLocation(String provider, Location loc) {
2048 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002049 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002050 MockProvider mockProvider = mMockProviders.get(provider);
2051 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002052 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2053 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002054 mockProvider.setLocation(loc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002055 }
2056 }
2057
2058 public void clearTestProviderLocation(String provider) {
2059 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002060 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002061 MockProvider mockProvider = mMockProviders.get(provider);
2062 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002063 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2064 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002065 mockProvider.clearLocation();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002066 }
2067 }
2068
2069 public void setTestProviderEnabled(String provider, boolean enabled) {
2070 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002071 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002072 MockProvider mockProvider = mMockProviders.get(provider);
2073 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002074 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2075 }
2076 if (enabled) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002077 mockProvider.enable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002078 mEnabledProviders.add(provider);
2079 mDisabledProviders.remove(provider);
2080 } else {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002081 mockProvider.disable();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002082 mEnabledProviders.remove(provider);
2083 mDisabledProviders.add(provider);
2084 }
2085 updateProvidersLocked();
2086 }
2087 }
2088
2089 public void clearTestProviderEnabled(String provider) {
2090 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002091 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002092 MockProvider mockProvider = mMockProviders.get(provider);
2093 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002094 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2095 }
2096 mEnabledProviders.remove(provider);
2097 mDisabledProviders.remove(provider);
2098 updateProvidersLocked();
2099 }
2100 }
2101
2102 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
2103 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002104 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002105 MockProvider mockProvider = mMockProviders.get(provider);
2106 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002107 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2108 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002109 mockProvider.setStatus(status, extras, updateTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 }
2111 }
2112
2113 public void clearTestProviderStatus(String provider) {
2114 checkMockPermissionsSafe();
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002115 synchronized (mLock) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002116 MockProvider mockProvider = mMockProviders.get(provider);
2117 if (mockProvider == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002118 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2119 }
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002120 mockProvider.clearStatus();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002121 }
2122 }
2123
2124 private void log(String log) {
2125 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2126 Log.d(TAG, log);
2127 }
2128 }
2129
2130 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2131 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2132 != PackageManager.PERMISSION_GRANTED) {
2133 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2134 + Binder.getCallingPid()
2135 + ", uid=" + Binder.getCallingUid());
2136 return;
2137 }
2138
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002139 synchronized (mLock) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 pw.println("Current Location Manager state:");
2141 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2142 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
2143 pw.println(" mGpsNavigating=" + mGpsNavigating);
2144 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 pw.println(" mCollector=" + mCollector);
2146 pw.println(" mAlarmInterval=" + mAlarmInterval
2147 + " mScreenOn=" + mScreenOn
2148 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2149 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2150 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
2151 pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired
2152 + " mCellWakeLockAcquired=" + mCellWakeLockAcquired);
2153 pw.println(" Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002154 int N = mReceivers.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 for (int i=0; i<N; i++) {
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002156 pw.println(" " + mReceivers.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002157 }
2158 pw.println(" Location Listeners:");
Mike Lockwood2f82c4e2009-04-17 08:24:10 -04002159 for (Receiver i : mReceivers.values()) {
2160 pw.println(" " + i + ":");
2161 for (Map.Entry<String,UpdateRecord> j : i.mUpdateRecords.entrySet()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002162 pw.println(" " + j.getKey() + ":");
2163 j.getValue().dump(pw, " ");
2164 }
2165 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002166 pw.println(" Records by Provider:");
2167 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2168 : mRecordsByProvider.entrySet()) {
2169 pw.println(" " + i.getKey() + ":");
2170 for (UpdateRecord j : i.getValue()) {
2171 pw.println(" " + j + ":");
2172 j.dump(pw, " ");
2173 }
2174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 pw.println(" Last Known Locations:");
2176 for (Map.Entry<String, Location> i
2177 : mLastKnownLocation.entrySet()) {
2178 pw.println(" " + i.getKey() + ":");
2179 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2180 }
2181 if (mProximityAlerts.size() > 0) {
2182 pw.println(" Proximity Alerts:");
2183 for (Map.Entry<PendingIntent, ProximityAlert> i
2184 : mProximityAlerts.entrySet()) {
2185 pw.println(" " + i.getKey() + ":");
2186 i.getValue().dump(pw, " ");
2187 }
2188 }
2189 if (mProximitiesEntered.size() > 0) {
2190 pw.println(" Proximities Entered:");
2191 for (ProximityAlert i : mProximitiesEntered) {
2192 pw.println(" " + i + ":");
2193 i.dump(pw, " ");
2194 }
2195 }
2196 pw.println(" mProximityListener=" + mProximityListener);
2197 if (mEnabledProviders.size() > 0) {
2198 pw.println(" Enabled Providers:");
2199 for (String i : mEnabledProviders) {
2200 pw.println(" " + i);
2201 }
2202
2203 }
2204 if (mDisabledProviders.size() > 0) {
2205 pw.println(" Disabled Providers:");
2206 for (String i : mDisabledProviders) {
2207 pw.println(" " + i);
2208 }
2209
2210 }
2211 if (mMockProviders.size() > 0) {
2212 pw.println(" Mock Providers:");
2213 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
Mike Lockwood7ec434e2009-03-27 07:46:48 -07002214 i.getValue().dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002215 }
2216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 }
2218 }
2219}