blob: bc8da93ce92af2512cb5ce58e6871206f14e462e [file] [log] [blame]
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001/*
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;
The Android Open Source Project3001a032009-02-19 10:57:31 -080021import java.io.FileDescriptor;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070022import java.io.FileReader;
23import java.io.FileWriter;
24import java.io.IOException;
The Android Open Source Project3001a032009-02-19 10:57:31 -080025import java.io.PrintWriter;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070026import java.util.ArrayList;
27import java.util.HashMap;
28import java.util.HashSet;
29import java.util.List;
The Android Open Source Project3001a032009-02-19 10:57:31 -080030import java.util.Map;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070031import java.util.Set;
32import java.util.regex.Pattern;
33
34import android.app.AlarmManager;
35import android.app.PendingIntent;
36import android.content.BroadcastReceiver;
37import android.content.ContentResolver;
38import android.content.Context;
39import android.content.Intent;
40import android.content.IntentFilter;
41import android.content.pm.PackageManager;
42import android.location.Address;
43import android.location.IGpsStatusListener;
44import android.location.ILocationListener;
45import android.location.ILocationManager;
46import android.location.Location;
47import android.location.LocationManager;
48import android.location.LocationProvider;
49import android.location.LocationProviderImpl;
50import android.net.ConnectivityManager;
The Android Open Source Project3001a032009-02-19 10:57:31 -080051import android.net.Uri;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070052import android.net.wifi.ScanResult;
53import android.net.wifi.WifiManager;
54import android.os.Binder;
55import android.os.Bundle;
56import android.os.Handler;
57import android.os.IBinder;
58import android.os.Message;
59import android.os.PowerManager;
60import android.os.RemoteException;
61import android.os.SystemClock;
62import android.provider.Settings;
63import android.telephony.CellLocation;
64import android.telephony.PhoneStateListener;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070065import android.telephony.TelephonyManager;
66import android.util.Config;
67import android.util.Log;
The Android Open Source Project3001a032009-02-19 10:57:31 -080068import android.util.PrintWriterPrinter;
69import android.util.SparseIntArray;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070070
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080071import com.android.internal.app.IBatteryStats;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070072import com.android.internal.location.CellState;
73import com.android.internal.location.GpsLocationProvider;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080074import com.android.internal.location.ILocationCollector;
75import com.android.internal.location.INetworkLocationManager;
76import com.android.internal.location.INetworkLocationProvider;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070077import com.android.internal.location.TrackProvider;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080078import com.android.server.am.BatteryStatsService;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070079
80/**
81 * The service class that manages LocationProviders and issues location
82 * updates and alerts.
83 *
84 * {@hide}
85 */
The Android Open Source Projectd24b8182009-02-10 15:44:00 -080086public class LocationManagerService extends ILocationManager.Stub
87 implements INetworkLocationManager {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -070088 private static final String TAG = "LocationManagerService";
89
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
96 // Time to wait after releasing a wake lock for clients to process location update,
97 // in milliseconds.
98 private static final long TIME_AFTER_WAKE_LOCK = 2 * 1000L;
99
100 // The last time a location was written, by provider name.
101 private HashMap<String,Long> mLastWriteTime = new HashMap<String,Long>();
102
103 private static final Pattern PATTERN_COMMA = Pattern.compile(",");
104
105 private static final String ACCESS_FINE_LOCATION =
106 android.Manifest.permission.ACCESS_FINE_LOCATION;
107 private static final String ACCESS_COARSE_LOCATION =
108 android.Manifest.permission.ACCESS_COARSE_LOCATION;
109 private static final String ACCESS_MOCK_LOCATION =
110 android.Manifest.permission.ACCESS_MOCK_LOCATION;
111 private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
112 android.Manifest.permission.ACCESS_LOCATION_EXTRA_COMMANDS;
113
114 // Set of providers that are explicitly enabled
115 private final Set<String> mEnabledProviders = new HashSet<String>();
116
117 // Set of providers that are explicitly disabled
118 private final Set<String> mDisabledProviders = new HashSet<String>();
119
120 // Locations, status values, and extras for mock providers
121 HashMap<String,MockProvider> mMockProviders = new HashMap<String,MockProvider>();
122 private final HashMap<String,Location> mMockProviderLocation = new HashMap<String,Location>();
123 private final HashMap<String,Integer> mMockProviderStatus = new HashMap<String,Integer>();
124 private final HashMap<String,Bundle> mMockProviderStatusExtras = new HashMap<String,Bundle>();
125 private final HashMap<String,Long> mMockProviderStatusUpdateTime = new HashMap<String,Long>();
126
127 private static boolean sProvidersLoaded = false;
128
129 private final Context mContext;
130 private GpsLocationProvider mGpsLocationProvider;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800131 private boolean mGpsNavigating;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800132 private LocationProviderImpl mNetworkLocationProvider;
133 private INetworkLocationProvider mNetworkLocationInterface;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700134 private LocationWorkerHandler mLocationHandler;
135
136 // Handler messages
137 private static final int MESSAGE_HEARTBEAT = 1;
138 private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
139 private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800140 private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700141
142 // Alarm manager and wakelock variables
143 private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
144 private final static String WAKELOCK_KEY = "LocationManagerService";
145 private final static String WIFILOCK_KEY = "LocationManagerService";
146 private AlarmManager mAlarmManager;
147 private long mAlarmInterval = 0;
148 private boolean mScreenOn = true;
149 private PowerManager.WakeLock mWakeLock = null;
150 private WifiManager.WifiLock mWifiLock = null;
151 private long mWakeLockAcquireTime = 0;
152 private boolean mWakeLockGpsReceived = true;
153 private boolean mWakeLockNetworkReceived = true;
154 private boolean mWifiWakeLockAcquired = false;
155 private boolean mCellWakeLockAcquired = false;
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800156
157 private final IBatteryStats mBatteryStats;
158
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700159 /**
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800160 * Mapping from listener IBinder/PendingIntent to local Listener wrappers.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700161 */
The Android Open Source Project3001a032009-02-19 10:57:31 -0800162 private final ArrayList<Receiver> mListeners = new ArrayList<Receiver>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700163
164 /**
The Android Open Source Project3001a032009-02-19 10:57:31 -0800165 * Used for reporting which UIDs are causing the GPS to run.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700166 */
The Android Open Source Project3001a032009-02-19 10:57:31 -0800167 private final SparseIntArray mReportedGpsUids = new SparseIntArray();
168 private int mReportedGpsSeq = 0;
169
170 /**
171 * Mapping from listener IBinder/PendingIntent to a map from provider name to UpdateRecord.
172 * This also serves as the lock for our state.
173 */
174 private final HashMap<Receiver,HashMap<String,UpdateRecord>> mLocationListeners =
175 new HashMap<Receiver,HashMap<String,UpdateRecord>>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700176
177 /**
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800178 * Mapping from listener IBinder/PendingIntent to a map from provider name to last broadcast
179 * location.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700180 */
The Android Open Source Project3001a032009-02-19 10:57:31 -0800181 private final HashMap<Receiver,HashMap<String,Location>> mLastFixBroadcast =
182 new HashMap<Receiver,HashMap<String,Location>>();
183 private final HashMap<Receiver,HashMap<String,Long>> mLastStatusBroadcast =
184 new HashMap<Receiver,HashMap<String,Long>>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700185
186 /**
187 * Mapping from provider name to all its UpdateRecords
188 */
The Android Open Source Project3001a032009-02-19 10:57:31 -0800189 private final HashMap<String,ArrayList<UpdateRecord>> mRecordsByProvider =
190 new HashMap<String,ArrayList<UpdateRecord>>();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700191
192 /**
193 * Mappings from provider name to object to use for current location. Locations
194 * contained in this list may not always be valid.
195 */
196 private final HashMap<String,Location> mLocationsByProvider =
197 new HashMap<String,Location>();
198
199 // Proximity listeners
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800200 private Receiver mProximityListener = null;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700201 private HashMap<PendingIntent,ProximityAlert> mProximityAlerts =
202 new HashMap<PendingIntent,ProximityAlert>();
203 private HashSet<ProximityAlert> mProximitiesEntered =
204 new HashSet<ProximityAlert>();
205
206 // Last known location for each provider
207 private HashMap<String,Location> mLastKnownLocation =
208 new HashMap<String,Location>();
209
210 // Battery status extras (from com.android.server.BatteryService)
211 private static final String BATTERY_EXTRA_SCALE = "scale";
212 private static final String BATTERY_EXTRA_LEVEL = "level";
213 private static final String BATTERY_EXTRA_PLUGGED = "plugged";
214
215 // Last known cell service state
216 private TelephonyManager mTelephonyManager;
The Android Open Source Project076357b2009-03-03 14:04:24 -0800217 private int mSignalStrength = -1;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700218
219 // Location collector
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800220 private ILocationCollector mCollector;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700221
222 // Wifi Manager
223 private WifiManager mWifiManager;
224
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800225 /**
226 * A wrapper class holding either an ILocationListener or a PendingIntent to receive
227 * location updates.
228 */
229 private final class Receiver implements IBinder.DeathRecipient {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700230 final ILocationListener mListener;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800231 final PendingIntent mPendingIntent;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800232 final int mUid;
233 final Object mKey;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700234
The Android Open Source Project3001a032009-02-19 10:57:31 -0800235 Receiver(ILocationListener listener, int uid) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700236 mListener = listener;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800237 mPendingIntent = null;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800238 mUid = uid;
239 mKey = listener.asBinder();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800240 }
241
The Android Open Source Project3001a032009-02-19 10:57:31 -0800242 Receiver(PendingIntent intent, int uid) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800243 mPendingIntent = intent;
244 mListener = null;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800245 mUid = uid;
246 mKey = intent;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800247 }
248
The Android Open Source Project3001a032009-02-19 10:57:31 -0800249 @Override
250 public boolean equals(Object otherObj) {
251 if (otherObj instanceof Receiver) {
252 return mKey.equals(
253 ((Receiver)otherObj).mKey);
254 }
255 return false;
256 }
257
258 @Override
259 public int hashCode() {
260 return mKey.hashCode();
261 }
262
263
264 @Override
265 public String toString() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800266 if (mListener != null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800267 return "Receiver{"
268 + Integer.toHexString(System.identityHashCode(this))
269 + " uid " + mUid + " Listener " + mKey + "}";
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800270 } else {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800271 return "Receiver{"
272 + Integer.toHexString(System.identityHashCode(this))
273 + " uid " + mUid + " Intent " + mKey + "}";
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800274 }
275 }
276
277 public boolean isListener() {
278 return mListener != null;
279 }
280
281 public boolean isPendingIntent() {
282 return mPendingIntent != null;
283 }
284
285 public ILocationListener getListener() {
286 if (mListener != null) {
287 return mListener;
288 }
289 throw new IllegalStateException("Request for non-existent listener");
290 }
291
292 public PendingIntent getPendingIntent() {
293 if (mPendingIntent != null) {
294 return mPendingIntent;
295 }
296 throw new IllegalStateException("Request for non-existent intent");
297 }
298
The Android Open Source Project3001a032009-02-19 10:57:31 -0800299 public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800300 if (mListener != null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800301 try {
302 mListener.onStatusChanged(provider, status, extras);
303 } catch (RemoteException e) {
304 return false;
305 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800306 } else {
307 Intent statusChanged = new Intent();
308 statusChanged.putExtras(extras);
309 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
310 try {
311 mPendingIntent.send(mContext, 0, statusChanged, null, null);
312 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800313 return false;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800314 }
315 }
The Android Open Source Project3001a032009-02-19 10:57:31 -0800316 return true;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800317 }
318
The Android Open Source Project3001a032009-02-19 10:57:31 -0800319 public boolean callLocationChangedLocked(Location location) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800320 if (mListener != null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800321 try {
322 mListener.onLocationChanged(location);
323 } catch (RemoteException e) {
324 return false;
325 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800326 } else {
327 Intent locationChanged = new Intent();
328 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED, location);
329 try {
330 mPendingIntent.send(mContext, 0, locationChanged, null, null);
331 } catch (PendingIntent.CanceledException e) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800332 return false;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800333 }
334 }
The Android Open Source Project3001a032009-02-19 10:57:31 -0800335 return true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700336 }
337
338 public void binderDied() {
339 if (Config.LOGD) {
340 Log.d(TAG, "Location listener died");
341 }
342 synchronized (mLocationListeners) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800343 removeUpdatesLocked(this);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700344 }
345 }
346 }
347
The Android Open Source Project3001a032009-02-19 10:57:31 -0800348 private Location readLastKnownLocationLocked(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700349 Location location = null;
350 String s = null;
351 try {
352 File f = new File(LocationManager.SYSTEM_DIR + "/location."
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800353 + provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700354 if (!f.exists()) {
355 return null;
356 }
357 BufferedReader reader = new BufferedReader(new FileReader(f), 256);
358 s = reader.readLine();
359 } catch (IOException e) {
360 Log.w(TAG, "Unable to read last known location", e);
361 }
362
363 if (s == null) {
364 return null;
365 }
366 try {
367 String[] tokens = PATTERN_COMMA.split(s);
368 int idx = 0;
369 long time = Long.parseLong(tokens[idx++]);
370 double latitude = Double.parseDouble(tokens[idx++]);
371 double longitude = Double.parseDouble(tokens[idx++]);
372 double altitude = Double.parseDouble(tokens[idx++]);
373 float bearing = Float.parseFloat(tokens[idx++]);
374 float speed = Float.parseFloat(tokens[idx++]);
375
376 location = new Location(provider);
377 location.setTime(time);
378 location.setLatitude(latitude);
379 location.setLongitude(longitude);
380 location.setAltitude(altitude);
381 location.setBearing(bearing);
382 location.setSpeed(speed);
383 } catch (NumberFormatException nfe) {
384 Log.e(TAG, "NumberFormatException reading last known location", nfe);
385 return null;
386 }
387
388 return location;
389 }
390
The Android Open Source Project3001a032009-02-19 10:57:31 -0800391 private void writeLastKnownLocationLocked(String provider,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700392 Location location) {
393 long now = SystemClock.elapsedRealtime();
394 Long last = mLastWriteTime.get(provider);
395 if ((last != null)
396 && (now - last.longValue() < MIN_LAST_KNOWN_LOCATION_TIME)) {
397 return;
398 }
399 mLastWriteTime.put(provider, now);
400
401 StringBuilder sb = new StringBuilder(100);
402 sb.append(location.getTime());
403 sb.append(',');
404 sb.append(location.getLatitude());
405 sb.append(',');
406 sb.append(location.getLongitude());
407 sb.append(',');
408 sb.append(location.getAltitude());
409 sb.append(',');
410 sb.append(location.getBearing());
411 sb.append(',');
412 sb.append(location.getSpeed());
413
414 FileWriter writer = null;
415 try {
416 File d = new File(LocationManager.SYSTEM_DIR);
417 if (!d.exists()) {
418 if (!d.mkdirs()) {
419 Log.w(TAG, "Unable to create directory to write location");
420 return;
421 }
422 }
423 File f = new File(LocationManager.SYSTEM_DIR + "/location." + provider);
424 writer = new FileWriter(f);
425 writer.write(sb.toString());
426 } catch (IOException e) {
427 Log.w(TAG, "Unable to write location", e);
428 } finally {
429 if (writer != null) {
430 try {
431 writer.close();
432 } catch (IOException e) {
433 Log.w(TAG, "Exception closing file", e);
434 }
435 }
436 }
437 }
438
439 /**
440 * Load providers from /data/location/<provider_name>/
441 * class
442 * kml
443 * nmea
444 * track
445 * location
446 * properties
447 */
448 private void loadProviders() {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800449 synchronized (mLocationListeners) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700450 if (sProvidersLoaded) {
451 return;
452 }
453
454 // Load providers
The Android Open Source Project3001a032009-02-19 10:57:31 -0800455 loadProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700456 sProvidersLoaded = true;
457 }
458 }
459
The Android Open Source Project3001a032009-02-19 10:57:31 -0800460 private void loadProvidersLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700461 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800462 _loadProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700463 } catch (Exception e) {
464 Log.e(TAG, "Exception loading providers:", e);
465 }
466 }
467
The Android Open Source Project3001a032009-02-19 10:57:31 -0800468 private void _loadProvidersLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700469 // Attempt to load "real" providers first
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700470 if (GpsLocationProvider.isSupported()) {
471 // Create a gps location provider
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800472 mGpsLocationProvider = new GpsLocationProvider(mContext);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700473 LocationProviderImpl.addProvider(mGpsLocationProvider);
474 }
475
476 // Load fake providers if real providers are not available
477 File f = new File(LocationManager.PROVIDER_DIR);
478 if (f.isDirectory()) {
479 File[] subdirs = f.listFiles();
480 for (int i = 0; i < subdirs.length; i++) {
481 if (!subdirs[i].isDirectory()) {
482 continue;
483 }
484
485 String name = subdirs[i].getName();
486
487 if (Config.LOGD) {
488 Log.d(TAG, "Found dir " + subdirs[i].getAbsolutePath());
489 Log.d(TAG, "name = " + name);
490 }
491
492 // Don't create a fake provider if a real provider exists
493 if (LocationProviderImpl.getProvider(name) == null) {
494 LocationProviderImpl provider = null;
495 try {
496 File classFile = new File(subdirs[i], "class");
497 // Look for a 'class' file
498 provider = LocationProviderImpl.loadFromClass(classFile);
499
500 // Look for an 'kml', 'nmea', or 'track' file
501 if (provider == null) {
502 // Load properties from 'properties' file, if present
503 File propertiesFile = new File(subdirs[i], "properties");
504
505 if (propertiesFile.exists()) {
506 provider = new TrackProvider(name);
507 ((TrackProvider)provider).readProperties(propertiesFile);
508
509 File kmlFile = new File(subdirs[i], "kml");
510 if (kmlFile.exists()) {
511 ((TrackProvider) provider).readKml(kmlFile);
512 } else {
513 File nmeaFile = new File(subdirs[i], "nmea");
514 if (nmeaFile.exists()) {
515 ((TrackProvider) provider).readNmea(name, nmeaFile);
516 } else {
517 File trackFile = new File(subdirs[i], "track");
518 if (trackFile.exists()) {
519 ((TrackProvider) provider).readTrack(trackFile);
520 }
521 }
522 }
523 }
524 }
525 if (provider != null) {
526 LocationProviderImpl.addProvider(provider);
527 }
528 // Grab the initial location of a TrackProvider and
529 // store it as the last known location for that provider
530 if (provider instanceof TrackProvider) {
531 TrackProvider tp = (TrackProvider) provider;
532 mLastKnownLocation.put(tp.getName(), tp.getInitialLocation());
533 }
534 } catch (Exception e) {
535 Log.e(TAG, "Exception loading provder " + name, e);
536 }
537 }
538 }
539 }
540
The Android Open Source Project3001a032009-02-19 10:57:31 -0800541 updateProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700542 }
543
544 /**
545 * @param context the context that the LocationManagerService runs in
546 */
547 public LocationManagerService(Context context) {
548 super();
549 mContext = context;
550 mLocationHandler = new LocationWorkerHandler();
551
552 if (Config.LOGD) {
553 Log.d(TAG, "Constructed LocationManager Service");
554 }
555
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800556 // Alarm manager, needs to be done before calling loadProviders() below
557 mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
558
559 // Create a wake lock, needs to be done before calling loadProviders() below
560 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
561 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800562
563 // Battery statistics service to be notified when GPS turns on or off
564 mBatteryStats = BatteryStatsService.getService();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800565
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700566 // Load providers
567 loadProviders();
568
569 // Listen for Radio changes
570 mTelephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
571 mTelephonyManager.listen(mPhoneStateListener,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800572 PhoneStateListener.LISTEN_CELL_LOCATION |
573 PhoneStateListener.LISTEN_SIGNAL_STRENGTH |
574 PhoneStateListener.LISTEN_DATA_CONNECTION_STATE);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700575
576 // Register for Network (Wifi or Mobile) updates
577 NetworkStateBroadcastReceiver networkReceiver = new NetworkStateBroadcastReceiver();
578 IntentFilter networkIntentFilter = new IntentFilter();
579 networkIntentFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
580 networkIntentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
581 networkIntentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
582 networkIntentFilter.addAction(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION);
583 context.registerReceiver(networkReceiver, networkIntentFilter);
584
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700585 // Register for power updates
586 PowerStateBroadcastReceiver powerStateReceiver = new PowerStateBroadcastReceiver();
587 IntentFilter intentFilter = new IntentFilter();
588 intentFilter.addAction(ALARM_INTENT);
589 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
590 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
591 intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
The Android Open Source Project3001a032009-02-19 10:57:31 -0800592 intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
593 intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700594 context.registerReceiver(powerStateReceiver, intentFilter);
595
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700596 // Get the wifi manager
597 mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
598
599 // Create a wifi lock for future use
The Android Open Source Project3001a032009-02-19 10:57:31 -0800600 mWifiLock = getWifiWakelockLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700601
602 // There might be an existing wifi scan available
603 if (mWifiManager != null) {
604 List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
605 if (wifiScanResults != null && wifiScanResults.size() != 0) {
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800606 if (mNetworkLocationInterface != null) {
607 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700608 }
609 }
610 }
611 }
612
The Android Open Source Projectda996f32009-02-13 12:57:50 -0800613 public void setInstallCallback(InstallCallback callback) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800614 synchronized (mLocationListeners) {
615 mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
616 Message m = Message.obtain(mLocationHandler,
617 MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
618 mLocationHandler.sendMessageAtFrontOfQueue(m);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800619 }
620 }
621
The Android Open Source Project3001a032009-02-19 10:57:31 -0800622 public void setNetworkLocationProvider(INetworkLocationProvider provider) {
623 synchronized (mLocationListeners) {
624 mNetworkLocationInterface = provider;
625 provider.addListener(getPackageNames());
626 mNetworkLocationProvider = (LocationProviderImpl)provider;
627 LocationProviderImpl.addProvider(mNetworkLocationProvider);
628 updateProvidersLocked();
629 }
630 }
631
632 public void setLocationCollector(ILocationCollector collector) {
633 synchronized (mLocationListeners) {
634 mCollector = collector;
635 if (mGpsLocationProvider != null) {
636 mGpsLocationProvider.setLocationCollector(mCollector);
637 }
638 }
639 }
640
641 private WifiManager.WifiLock getWifiWakelockLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700642 if (mWifiLock == null && mWifiManager != null) {
The Android Open Source Projectb7986892009-01-09 17:51:23 -0800643 mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700644 mWifiLock.setReferenceCounted(false);
645 }
646 return mWifiLock;
647 }
648
The Android Open Source Project3001a032009-02-19 10:57:31 -0800649 private boolean isAllowedBySettingsLocked(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700650 if (mEnabledProviders.contains(provider)) {
651 return true;
652 }
653 if (mDisabledProviders.contains(provider)) {
654 return false;
655 }
656 // Use system settings
657 ContentResolver resolver = mContext.getContentResolver();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800658 String allowedProviders = Settings.Secure.getString(resolver,
659 Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700660
661 return ((allowedProviders != null) && (allowedProviders.contains(provider)));
662 }
663
The Android Open Source Project3001a032009-02-19 10:57:31 -0800664 private void checkPermissionsSafe(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700665 if (LocationManager.GPS_PROVIDER.equals(provider)
666 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
667 != PackageManager.PERMISSION_GRANTED)) {
668 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
669 }
670 if (LocationManager.NETWORK_PROVIDER.equals(provider)
671 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
672 != PackageManager.PERMISSION_GRANTED)
673 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
674 != PackageManager.PERMISSION_GRANTED)) {
675 throw new SecurityException(
676 "Requires ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION permission");
677 }
678 }
679
The Android Open Source Project3001a032009-02-19 10:57:31 -0800680 private boolean isAllowedProviderSafe(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700681 if (LocationManager.GPS_PROVIDER.equals(provider)
682 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
683 != PackageManager.PERMISSION_GRANTED)) {
684 return false;
685 }
686 if (LocationManager.NETWORK_PROVIDER.equals(provider)
687 && (mContext.checkCallingPermission(ACCESS_FINE_LOCATION)
688 != PackageManager.PERMISSION_GRANTED)
689 && (mContext.checkCallingPermission(ACCESS_COARSE_LOCATION)
690 != PackageManager.PERMISSION_GRANTED)) {
691 return false;
692 }
693
694 return true;
695 }
696
697 private String[] getPackageNames() {
698 // Since a single UID may correspond to multiple packages, this can only be used as an
699 // approximation for tracking
700 return mContext.getPackageManager().getPackagesForUid(Binder.getCallingUid());
701 }
702
703 public List<String> getAllProviders() {
704 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800705 synchronized (mLocationListeners) {
706 return _getAllProvidersLocked();
707 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700708 } catch (SecurityException se) {
709 throw se;
710 } catch (Exception e) {
711 Log.e(TAG, "getAllProviders got exception:", e);
712 return null;
713 }
714 }
715
The Android Open Source Project3001a032009-02-19 10:57:31 -0800716 private List<String> _getAllProvidersLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700717 if (Config.LOGD) {
718 Log.d(TAG, "getAllProviders");
719 }
720 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
721 ArrayList<String> out = new ArrayList<String>(providers.size());
722
723 for (LocationProviderImpl p : providers) {
724 out.add(p.getName());
725 }
726 return out;
727 }
728
729 public List<String> getProviders(boolean enabledOnly) {
730 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800731 synchronized (mLocationListeners) {
732 return _getProvidersLocked(enabledOnly);
733 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700734 } catch (SecurityException se) {
735 throw se;
736 } catch (Exception e) {
737 Log.e(TAG, "getProviders gotString exception:", e);
738 return null;
739 }
740 }
741
The Android Open Source Project3001a032009-02-19 10:57:31 -0800742 private List<String> _getProvidersLocked(boolean enabledOnly) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700743 if (Config.LOGD) {
744 Log.d(TAG, "getProviders");
745 }
746 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
747 ArrayList<String> out = new ArrayList<String>();
748
749 for (LocationProviderImpl p : providers) {
750 String name = p.getName();
The Android Open Source Project3001a032009-02-19 10:57:31 -0800751 if (isAllowedProviderSafe(name)) {
752 if (enabledOnly && !isAllowedBySettingsLocked(name)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700753 continue;
754 }
755 out.add(name);
756 }
757 }
758 return out;
759 }
760
761 public void updateProviders() {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800762 synchronized (mLocationListeners) {
763 updateProvidersLocked();
764 }
765 }
766
767 private void updateProvidersLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700768 for (LocationProviderImpl p : LocationProviderImpl.getProviders()) {
769 boolean isEnabled = p.isEnabled();
770 String name = p.getName();
The Android Open Source Project3001a032009-02-19 10:57:31 -0800771 boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700772
773 // Collection is only allowed when network provider is being used
The Android Open Source Projectd24b8182009-02-10 15:44:00 -0800774 if (mCollector != null &&
775 p.getName().equals(LocationManager.NETWORK_PROVIDER)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700776 mCollector.updateNetworkProviderStatus(shouldBeEnabled);
777 }
778
779 if (isEnabled && !shouldBeEnabled) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800780 updateProviderListenersLocked(name, false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700781 } else if (!isEnabled && shouldBeEnabled) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800782 updateProviderListenersLocked(name, true);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700783 }
784
785 }
786 }
787
The Android Open Source Project3001a032009-02-19 10:57:31 -0800788 private void updateProviderListenersLocked(String provider, boolean enabled) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700789 int listeners = 0;
790
791 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
792 if (p == null) {
793 return;
794 }
795
The Android Open Source Project3001a032009-02-19 10:57:31 -0800796 ArrayList<Receiver> deadReceivers = null;
797
798 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
799 if (records != null) {
800 final int N = records.size();
801 for (int i=0; i<N; i++) {
802 UpdateRecord record = records.get(i);
803 // Sends a notification message to the receiver
804 try {
805 Receiver receiver = record.mReceiver;
806 if (receiver.isListener()) {
807 if (enabled) {
808 receiver.getListener().onProviderEnabled(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700809 } else {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800810 receiver.getListener().onProviderDisabled(provider);
811 }
812 } else {
813 Intent providerIntent = new Intent();
814 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
815 try {
816 receiver.getPendingIntent().send(mContext, 0,
817 providerIntent, null, null);
818 } catch (PendingIntent.CanceledException e) {
819 if (deadReceivers == null) {
820 deadReceivers = new ArrayList<Receiver>();
821 deadReceivers.add(receiver);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800822 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700823 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700824 }
The Android Open Source Project3001a032009-02-19 10:57:31 -0800825 } catch (RemoteException e) {
826 // The death link will clean this up.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700827 }
The Android Open Source Project3001a032009-02-19 10:57:31 -0800828 listeners++;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700829 }
830 }
831
The Android Open Source Project3001a032009-02-19 10:57:31 -0800832 if (deadReceivers != null) {
833 for (int i=deadReceivers.size()-1; i>=0; i--) {
834 removeUpdatesLocked(deadReceivers.get(i));
835 }
836 }
837
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700838 if (enabled) {
839 p.enable();
840 if (listeners > 0) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800841 p.setMinTime(getMinTimeLocked(provider));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700842 p.enableLocationTracking(true);
The Android Open Source Project3001a032009-02-19 10:57:31 -0800843 updateWakelockStatusLocked(mScreenOn);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700844 }
845 } else {
846 p.enableLocationTracking(false);
The Android Open Source Project3001a032009-02-19 10:57:31 -0800847 if (p == mGpsLocationProvider) {
848 mGpsNavigating = false;
849 reportStopGpsLocked();
850 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700851 p.disable();
The Android Open Source Project3001a032009-02-19 10:57:31 -0800852 updateWakelockStatusLocked(mScreenOn);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700853 }
854
855 if (enabled && listeners > 0) {
856 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
857 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
858 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
859 } else {
860 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
861 }
862 }
863
The Android Open Source Project3001a032009-02-19 10:57:31 -0800864 private long getMinTimeLocked(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700865 long minTime = Long.MAX_VALUE;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800866 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
867 if (records != null) {
868 for (int i=records.size()-1; i>=0; i--) {
869 minTime = Math.min(minTime, records.get(i).mMinTime);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700870 }
871 }
872 return minTime;
873 }
874
875 private class UpdateRecord {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800876 final String mProvider;
877 final Receiver mReceiver;
878 final long mMinTime;
879 final float mMinDistance;
880 final int mUid;
881 final String[] mPackages;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700882
The Android Open Source Project3001a032009-02-19 10:57:31 -0800883 /**
884 * Note: must be constructed with lock held.
885 */
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800886 UpdateRecord(String provider, long minTime, float minDistance,
The Android Open Source Project3001a032009-02-19 10:57:31 -0800887 Receiver receiver, int uid, String[] packages) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700888 mProvider = provider;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800889 mReceiver = receiver;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700890 mMinTime = minTime;
891 mMinDistance = minDistance;
The Android Open Source Project3001a032009-02-19 10:57:31 -0800892 mUid = uid;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700893 mPackages = packages;
894
The Android Open Source Project3001a032009-02-19 10:57:31 -0800895 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
896 if (records == null) {
897 records = new ArrayList<UpdateRecord>();
898 mRecordsByProvider.put(provider, records);
899 }
900 if (!records.contains(this)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700901 records.add(this);
902 }
903 }
904
905 /**
906 * Method to be called when a record will no longer be used. Calling this multiple times
907 * must have the same effect as calling it once.
908 */
The Android Open Source Project3001a032009-02-19 10:57:31 -0800909 void disposeLocked() {
910 ArrayList<UpdateRecord> records = mRecordsByProvider.get(this.mProvider);
911 records.remove(this);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700912 }
913
The Android Open Source Project3001a032009-02-19 10:57:31 -0800914 @Override
915 public String toString() {
916 return "UpdateRecord{"
917 + Integer.toHexString(System.identityHashCode(this))
918 + " " + mProvider + " " + mReceiver + "}";
919 }
920
921 void dump(PrintWriter pw, String prefix) {
922 pw.println(prefix + this);
923 pw.println(prefix + "mProvider=" + mProvider + " mReceiver=" + mReceiver);
924 pw.println(prefix + "mMinTime=" + mMinTime + " mMinDistance=" + mMinDistance);
925 StringBuilder sb = new StringBuilder();
926 if (mPackages != null) {
927 for (int i=0; i<mPackages.length; i++) {
928 if (i > 0) sb.append(", ");
929 sb.append(mPackages[i]);
930 }
931 }
932 pw.println(prefix + "mUid=" + mUid + " mPackages=" + sb);
933 }
934
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700935 /**
936 * Calls dispose().
937 */
938 @Override protected void finalize() {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800939 synchronized (mLocationListeners) {
940 disposeLocked();
941 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700942 }
943 }
944
945 public void requestLocationUpdates(String provider,
946 long minTime, float minDistance, ILocationListener listener) {
947
948 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800949 synchronized (mLocationListeners) {
950 requestLocationUpdatesLocked(provider, minTime, minDistance,
951 new Receiver(listener, Binder.getCallingUid()));
952 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800953 } catch (SecurityException se) {
954 throw se;
955 } catch (Exception e) {
956 Log.e(TAG, "requestUpdates got exception:", e);
957 }
958 }
959
960 public void requestLocationUpdatesPI(String provider,
961 long minTime, float minDistance, PendingIntent intent) {
962 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800963 synchronized (mLocationListeners) {
964 requestLocationUpdatesLocked(provider, minTime, minDistance,
965 new Receiver(intent, Binder.getCallingUid()));
966 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700967 } catch (SecurityException se) {
968 throw se;
969 } catch (Exception e) {
970 Log.e(TAG, "requestUpdates got exception:", e);
971 }
972 }
973
The Android Open Source Project3001a032009-02-19 10:57:31 -0800974 private void requestLocationUpdatesLocked(String provider,
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -0800975 long minTime, float minDistance, Receiver receiver) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700976 if (Config.LOGD) {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800977 Log.d(TAG, "_requestLocationUpdates: listener = " + receiver);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700978 }
979
980 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
981 if (impl == null) {
982 throw new IllegalArgumentException("provider=" + provider);
983 }
984
The Android Open Source Project3001a032009-02-19 10:57:31 -0800985 checkPermissionsSafe(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700986
987 String[] packages = getPackageNames();
988
989 // so wakelock calls will succeed
The Android Open Source Project3001a032009-02-19 10:57:31 -0800990 final int callingUid = Binder.getCallingUid();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -0700991 long identity = Binder.clearCallingIdentity();
992 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -0800993 UpdateRecord r = new UpdateRecord(provider, minTime, minDistance,
994 receiver, callingUid, packages);
995 if (!mListeners.contains(receiver)) {
996 try {
997 if (receiver.isListener()) {
998 receiver.getListener().asBinder().linkToDeath(receiver, 0);
999 }
1000 mListeners.add(receiver);
1001 } catch (RemoteException e) {
1002 return;
1003 }
1004 }
1005
1006 HashMap<String,UpdateRecord> records = mLocationListeners.get(receiver);
1007 if (records == null) {
1008 records = new HashMap<String,UpdateRecord>();
1009 mLocationListeners.put(receiver, records);
1010 }
1011 UpdateRecord oldRecord = records.put(provider, r);
1012 if (oldRecord != null) {
1013 oldRecord.disposeLocked();
1014 }
1015
1016 boolean isProviderEnabled = isAllowedBySettingsLocked(provider);
1017 if (isProviderEnabled) {
1018 long minTimeForProvider = getMinTimeLocked(provider);
1019 impl.setMinTime(minTimeForProvider);
1020 impl.enableLocationTracking(true);
1021 updateWakelockStatusLocked(mScreenOn);
1022
1023 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1024 if (mGpsNavigating) {
1025 updateReportedGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001026 }
1027 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001028
1029 // Clear heartbeats if any before starting a new one
1030 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
1031 Message m = Message.obtain(mLocationHandler, MESSAGE_HEARTBEAT, provider);
1032 mLocationHandler.sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
1033 } else {
1034 try {
1035 // Notify the listener that updates are currently disabled
1036 if (receiver.isListener()) {
1037 receiver.getListener().onProviderDisabled(provider);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001038 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001039 } catch(RemoteException e) {
1040 Log.w(TAG, "RemoteException calling onProviderDisabled on " +
1041 receiver.getListener());
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001042 }
1043 }
1044 } finally {
1045 Binder.restoreCallingIdentity(identity);
1046 }
1047 }
1048
1049 public void removeUpdates(ILocationListener listener) {
1050 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001051 synchronized (mLocationListeners) {
1052 removeUpdatesLocked(new Receiver(listener, Binder.getCallingUid()));
1053 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001054 } catch (SecurityException se) {
1055 throw se;
1056 } catch (Exception e) {
1057 Log.e(TAG, "removeUpdates got exception:", e);
1058 }
1059 }
1060
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001061 public void removeUpdatesPI(PendingIntent intent) {
1062 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001063 synchronized (mLocationListeners) {
1064 removeUpdatesLocked(new Receiver(intent, Binder.getCallingUid()));
1065 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001066 } catch (SecurityException se) {
1067 throw se;
1068 } catch (Exception e) {
1069 Log.e(TAG, "removeUpdates got exception:", e);
1070 }
1071 }
1072
The Android Open Source Project3001a032009-02-19 10:57:31 -08001073 private void removeUpdatesLocked(Receiver receiver) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001074 if (Config.LOGD) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001075 Log.d(TAG, "_removeUpdates: listener = " + receiver);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001076 }
1077
1078 // so wakelock calls will succeed
The Android Open Source Project3001a032009-02-19 10:57:31 -08001079 final int callingUid = Binder.getCallingUid();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001080 long identity = Binder.clearCallingIdentity();
1081 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001082 int idx = mListeners.indexOf(receiver);
1083 if (idx >= 0) {
1084 Receiver myReceiver = mListeners.remove(idx);
1085 if (myReceiver.isListener()) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001086 myReceiver.getListener().asBinder().unlinkToDeath(myReceiver, 0);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001087 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001088 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001089
1090 // Record which providers were associated with this listener
1091 HashSet<String> providers = new HashSet<String>();
1092 HashMap<String,UpdateRecord> oldRecords = mLocationListeners.get(receiver);
1093 if (oldRecords != null) {
1094 // Call dispose() on the obsolete update records.
1095 for (UpdateRecord record : oldRecords.values()) {
1096 if (record.mProvider.equals(LocationManager.NETWORK_PROVIDER)) {
1097 if (mNetworkLocationInterface != null) {
1098 mNetworkLocationInterface.removeListener(record.mPackages);
1099 }
1100 }
1101 record.disposeLocked();
1102 }
1103 // Accumulate providers
1104 providers.addAll(oldRecords.keySet());
1105 }
1106
1107 mLocationListeners.remove(receiver);
1108 mLastFixBroadcast.remove(receiver);
1109 mLastStatusBroadcast.remove(receiver);
1110
1111 // See if the providers associated with this listener have any
1112 // other listeners; if one does, inform it of the new smallest minTime
1113 // value; if one does not, disable location tracking for it
1114 for (String provider : providers) {
1115 // If provider is already disabled, don't need to do anything
1116 if (!isAllowedBySettingsLocked(provider)) {
1117 continue;
1118 }
1119
1120 boolean hasOtherListener = false;
1121 ArrayList<UpdateRecord> recordsForProvider = mRecordsByProvider.get(provider);
1122 if (recordsForProvider != null && recordsForProvider.size() > 0) {
1123 hasOtherListener = true;
1124 }
1125
1126 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1127 if (p != null) {
1128 if (hasOtherListener) {
1129 p.setMinTime(getMinTimeLocked(provider));
1130 } else {
1131 mLocationHandler.removeMessages(MESSAGE_HEARTBEAT, provider);
1132 p.enableLocationTracking(false);
1133 }
1134
1135 if (p == mGpsLocationProvider && mGpsNavigating) {
1136 updateReportedGpsLocked();
1137 }
1138 }
1139 }
1140
1141 updateWakelockStatusLocked(mScreenOn);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001142 } finally {
1143 Binder.restoreCallingIdentity(identity);
1144 }
1145 }
1146
1147 public boolean addGpsStatusListener(IGpsStatusListener listener) {
1148 if (mGpsLocationProvider == null) {
1149 return false;
1150 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001151 if (mContext.checkCallingPermission(ACCESS_FINE_LOCATION) !=
The Android Open Source Project3001a032009-02-19 10:57:31 -08001152 PackageManager.PERMISSION_GRANTED) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001153 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1154 }
1155
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001156 try {
1157 mGpsLocationProvider.addGpsStatusListener(listener);
1158 } catch (RemoteException e) {
1159 Log.w(TAG, "RemoteException in addGpsStatusListener");
1160 return false;
1161 }
1162 return true;
1163 }
1164
1165 public void removeGpsStatusListener(IGpsStatusListener listener) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001166 synchronized (mLocationListeners) {
1167 mGpsLocationProvider.removeGpsStatusListener(listener);
1168 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001169 }
1170
1171 public boolean sendExtraCommand(String provider, String command, Bundle extras) {
1172 // first check for permission to the provider
The Android Open Source Project3001a032009-02-19 10:57:31 -08001173 checkPermissionsSafe(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001174 // and check for ACCESS_LOCATION_EXTRA_COMMANDS
1175 if ((mContext.checkCallingPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
1176 != PackageManager.PERMISSION_GRANTED)) {
1177 throw new SecurityException("Requires ACCESS_LOCATION_EXTRA_COMMANDS permission");
1178 }
1179
The Android Open Source Project3001a032009-02-19 10:57:31 -08001180 synchronized (mLocationListeners) {
1181 LocationProviderImpl impl = LocationProviderImpl.getProvider(provider);
1182 if (provider == null) {
1183 return false;
1184 }
1185
1186 return impl.sendExtraCommand(command, extras);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001187 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001188 }
1189
1190 class ProximityAlert {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001191 final int mUid;
1192 final double mLatitude;
1193 final double mLongitude;
1194 final float mRadius;
1195 final long mExpiration;
1196 final PendingIntent mIntent;
1197 final Location mLocation;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001198
The Android Open Source Project3001a032009-02-19 10:57:31 -08001199 public ProximityAlert(int uid, double latitude, double longitude,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001200 float radius, long expiration, PendingIntent intent) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001201 mUid = uid;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001202 mLatitude = latitude;
1203 mLongitude = longitude;
1204 mRadius = radius;
1205 mExpiration = expiration;
1206 mIntent = intent;
1207
1208 mLocation = new Location("");
1209 mLocation.setLatitude(latitude);
1210 mLocation.setLongitude(longitude);
1211 }
1212
The Android Open Source Project3001a032009-02-19 10:57:31 -08001213 long getExpiration() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001214 return mExpiration;
1215 }
1216
The Android Open Source Project3001a032009-02-19 10:57:31 -08001217 PendingIntent getIntent() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001218 return mIntent;
1219 }
1220
The Android Open Source Project3001a032009-02-19 10:57:31 -08001221 boolean isInProximity(double latitude, double longitude) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001222 Location loc = new Location("");
1223 loc.setLatitude(latitude);
1224 loc.setLongitude(longitude);
1225
1226 double radius = loc.distanceTo(mLocation);
1227 return radius <= mRadius;
1228 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001229
1230 @Override
1231 public String toString() {
1232 return "ProximityAlert{"
1233 + Integer.toHexString(System.identityHashCode(this))
1234 + " uid " + mUid + mIntent + "}";
1235 }
1236
1237 void dump(PrintWriter pw, String prefix) {
1238 pw.println(prefix + this);
1239 pw.println(prefix + "mLatitude=" + mLatitude + " mLongitude=" + mLongitude);
1240 pw.println(prefix + "mRadius=" + mRadius + " mExpiration=" + mExpiration);
1241 pw.println(prefix + "mIntent=" + mIntent);
1242 pw.println(prefix + "mLocation:");
1243 mLocation.dump(new PrintWriterPrinter(pw), prefix + " ");
1244 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001245 }
1246
1247 // Listener for receiving locations to trigger proximity alerts
1248 class ProximityListener extends ILocationListener.Stub {
1249
1250 boolean isGpsAvailable = false;
1251
The Android Open Source Project3001a032009-02-19 10:57:31 -08001252 // Note: this is called with the lock held.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001253 public void onLocationChanged(Location loc) {
1254
1255 // If Gps is available, then ignore updates from NetworkLocationProvider
1256 if (loc.getProvider().equals(LocationManager.GPS_PROVIDER)) {
1257 isGpsAvailable = true;
1258 }
1259 if (isGpsAvailable && loc.getProvider().equals(LocationManager.NETWORK_PROVIDER)) {
1260 return;
1261 }
1262
1263 // Process proximity alerts
1264 long now = System.currentTimeMillis();
1265 double latitude = loc.getLatitude();
1266 double longitude = loc.getLongitude();
1267 ArrayList<PendingIntent> intentsToRemove = null;
1268
1269 for (ProximityAlert alert : mProximityAlerts.values()) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001270 PendingIntent intent = alert.getIntent();
1271 long expiration = alert.getExpiration();
1272
1273 if ((expiration == -1) || (now <= expiration)) {
1274 boolean entered = mProximitiesEntered.contains(alert);
1275 boolean inProximity =
1276 alert.isInProximity(latitude, longitude);
1277 if (!entered && inProximity) {
1278 if (Config.LOGD) {
1279 Log.i(TAG, "Entered alert");
1280 }
1281 mProximitiesEntered.add(alert);
1282 Intent enteredIntent = new Intent();
1283 enteredIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, true);
1284 try {
1285 intent.send(mContext, 0, enteredIntent, null, null);
1286 } catch (PendingIntent.CanceledException e) {
1287 if (Config.LOGD) {
1288 Log.i(TAG, "Canceled proximity alert: " + alert, e);
1289 }
1290 if (intentsToRemove == null) {
1291 intentsToRemove = new ArrayList<PendingIntent>();
1292 }
1293 intentsToRemove.add(intent);
1294 }
1295 } else if (entered && !inProximity) {
1296 if (Config.LOGD) {
1297 Log.i(TAG, "Exited alert");
1298 }
1299 mProximitiesEntered.remove(alert);
1300 Intent exitedIntent = new Intent();
1301 exitedIntent.putExtra(LocationManager.KEY_PROXIMITY_ENTERING, false);
1302 try {
1303 intent.send(mContext, 0, exitedIntent, null, null);
1304 } catch (PendingIntent.CanceledException e) {
1305 if (Config.LOGD) {
1306 Log.i(TAG, "Canceled proximity alert: " + alert, e);
1307 }
1308 if (intentsToRemove == null) {
1309 intentsToRemove = new ArrayList<PendingIntent>();
1310 }
1311 intentsToRemove.add(intent);
1312 }
1313 }
1314 } else {
1315 // Mark alert for expiration
1316 if (Config.LOGD) {
1317 Log.i(TAG, "Expiring proximity alert: " + alert);
1318 }
1319 if (intentsToRemove == null) {
1320 intentsToRemove = new ArrayList<PendingIntent>();
1321 }
1322 intentsToRemove.add(alert.getIntent());
1323 }
1324 }
1325
1326 // Remove expired alerts
1327 if (intentsToRemove != null) {
1328 for (PendingIntent i : intentsToRemove) {
1329 mProximityAlerts.remove(i);
1330 ProximityAlert alert = mProximityAlerts.get(i);
1331 mProximitiesEntered.remove(alert);
1332 }
1333 }
1334
1335 }
1336
The Android Open Source Project3001a032009-02-19 10:57:31 -08001337 // Note: this is called with the lock held.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001338 public void onProviderDisabled(String provider) {
1339 if (provider.equals(LocationManager.GPS_PROVIDER)) {
1340 isGpsAvailable = false;
1341 }
1342 }
1343
The Android Open Source Project3001a032009-02-19 10:57:31 -08001344 // Note: this is called with the lock held.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001345 public void onProviderEnabled(String provider) {
1346 // ignore
1347 }
1348
The Android Open Source Project3001a032009-02-19 10:57:31 -08001349 // Note: this is called with the lock held.
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001350 public void onStatusChanged(String provider, int status, Bundle extras) {
1351 if ((provider.equals(LocationManager.GPS_PROVIDER)) &&
1352 (status != LocationProvider.AVAILABLE)) {
1353 isGpsAvailable = false;
1354 }
1355 }
1356 }
1357
1358 public void addProximityAlert(double latitude, double longitude,
1359 float radius, long expiration, PendingIntent intent) {
1360 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001361 synchronized (mLocationListeners) {
1362 addProximityAlertLocked(latitude, longitude, radius, expiration, intent);
1363 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001364 } catch (SecurityException se) {
1365 throw se;
1366 } catch (Exception e) {
1367 Log.e(TAG, "addProximityAlert got exception:", e);
1368 }
1369 }
1370
The Android Open Source Project3001a032009-02-19 10:57:31 -08001371 private void addProximityAlertLocked(double latitude, double longitude,
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001372 float radius, long expiration, PendingIntent intent) {
1373 if (Config.LOGD) {
1374 Log.d(TAG, "addProximityAlert: latitude = " + latitude +
1375 ", longitude = " + longitude +
1376 ", expiration = " + expiration +
1377 ", intent = " + intent);
1378 }
1379
1380 // Require ability to access all providers for now
The Android Open Source Project3001a032009-02-19 10:57:31 -08001381 if (!isAllowedProviderSafe(LocationManager.GPS_PROVIDER) ||
1382 !isAllowedProviderSafe(LocationManager.NETWORK_PROVIDER)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001383 throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
1384 }
1385
1386 if (expiration != -1) {
1387 expiration += System.currentTimeMillis();
1388 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001389 ProximityAlert alert = new ProximityAlert(Binder.getCallingUid(),
1390 latitude, longitude, radius, expiration, intent);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001391 mProximityAlerts.put(intent, alert);
1392
1393 if (mProximityListener == null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001394 mProximityListener = new Receiver(new ProximityListener(), -1);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001395
1396 LocationProvider provider = LocationProviderImpl.getProvider(
1397 LocationManager.GPS_PROVIDER);
1398 if (provider != null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001399 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001400 }
1401
1402 provider =
1403 LocationProviderImpl.getProvider(LocationManager.NETWORK_PROVIDER);
1404 if (provider != null) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001405 requestLocationUpdatesLocked(provider.getName(), 1000L, 1.0f, mProximityListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001406 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001407 } else if (mGpsNavigating) {
1408 updateReportedGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001409 }
1410 }
1411
1412 public void removeProximityAlert(PendingIntent intent) {
1413 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001414 synchronized (mLocationListeners) {
1415 removeProximityAlertLocked(intent);
1416 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001417 } catch (SecurityException se) {
1418 throw se;
1419 } catch (Exception e) {
1420 Log.e(TAG, "removeProximityAlert got exception:", e);
1421 }
1422 }
1423
The Android Open Source Project3001a032009-02-19 10:57:31 -08001424 private void removeProximityAlertLocked(PendingIntent intent) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001425 if (Config.LOGD) {
1426 Log.d(TAG, "removeProximityAlert: intent = " + intent);
1427 }
1428
1429 mProximityAlerts.remove(intent);
1430 if (mProximityAlerts.size() == 0) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001431 removeUpdatesLocked(mProximityListener);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001432 mProximityListener = null;
The Android Open Source Project3001a032009-02-19 10:57:31 -08001433 } else if (mGpsNavigating) {
1434 updateReportedGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001435 }
1436 }
1437
1438 /**
1439 * @return null if the provider does not exits
1440 * @throw SecurityException if the provider is not allowed to be
1441 * accessed by the caller
1442 */
1443 public Bundle getProviderInfo(String provider) {
1444 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001445 synchronized (mLocationListeners) {
1446 return _getProviderInfoLocked(provider);
1447 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001448 } catch (SecurityException se) {
1449 throw se;
1450 } catch (Exception e) {
1451 Log.e(TAG, "_getProviderInfo got exception:", e);
1452 return null;
1453 }
1454 }
1455
The Android Open Source Project3001a032009-02-19 10:57:31 -08001456 private Bundle _getProviderInfoLocked(String provider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001457 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1458 if (p == null) {
1459 return null;
1460 }
1461
The Android Open Source Project3001a032009-02-19 10:57:31 -08001462 checkPermissionsSafe(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001463
1464 Bundle b = new Bundle();
1465 b.putBoolean("network", p.requiresNetwork());
1466 b.putBoolean("satellite", p.requiresSatellite());
1467 b.putBoolean("cell", p.requiresCell());
1468 b.putBoolean("cost", p.hasMonetaryCost());
1469 b.putBoolean("altitude", p.supportsAltitude());
1470 b.putBoolean("speed", p.supportsSpeed());
1471 b.putBoolean("bearing", p.supportsBearing());
1472 b.putInt("power", p.getPowerRequirement());
1473 b.putInt("accuracy", p.getAccuracy());
1474
1475 return b;
1476 }
1477
1478 public boolean isProviderEnabled(String provider) {
1479 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001480 synchronized (mLocationListeners) {
1481 return _isProviderEnabledLocked(provider);
1482 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001483 } catch (SecurityException se) {
1484 throw se;
1485 } catch (Exception e) {
1486 Log.e(TAG, "isProviderEnabled got exception:", e);
1487 return false;
1488 }
1489 }
1490
The Android Open Source Project3001a032009-02-19 10:57:31 -08001491 private boolean _isProviderEnabledLocked(String provider) {
1492 checkPermissionsSafe(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001493
1494 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1495 if (p == null) {
1496 throw new IllegalArgumentException("provider=" + provider);
1497 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001498 return isAllowedBySettingsLocked(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001499 }
1500
1501 public Location getLastKnownLocation(String provider) {
1502 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001503 synchronized (mLocationListeners) {
1504 return _getLastKnownLocationLocked(provider);
1505 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001506 } catch (SecurityException se) {
1507 throw se;
1508 } catch (Exception e) {
1509 Log.e(TAG, "getLastKnownLocation got exception:", e);
1510 return null;
1511 }
1512 }
1513
The Android Open Source Project3001a032009-02-19 10:57:31 -08001514 private Location _getLastKnownLocationLocked(String provider) {
1515 checkPermissionsSafe(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001516
1517 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1518 if (p == null) {
1519 throw new IllegalArgumentException("provider=" + provider);
1520 }
1521
The Android Open Source Project3001a032009-02-19 10:57:31 -08001522 if (!isAllowedBySettingsLocked(provider)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001523 return null;
1524 }
1525
1526 Location location = mLastKnownLocation.get(provider);
1527 if (location == null) {
1528 // Get the persistent last known location for the provider
The Android Open Source Project3001a032009-02-19 10:57:31 -08001529 location = readLastKnownLocationLocked(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001530 if (location != null) {
1531 mLastKnownLocation.put(provider, location);
1532 }
1533 }
1534
1535 return location;
1536 }
1537
The Android Open Source Project3001a032009-02-19 10:57:31 -08001538 private static boolean shouldBroadcastSafe(Location loc, Location lastLoc, UpdateRecord record) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001539 // Always broadcast the first update
1540 if (lastLoc == null) {
1541 return true;
1542 }
1543
1544 // Don't broadcast same location again regardless of condition
1545 // TODO - we should probably still rebroadcast if user explicitly sets a minTime > 0
1546 if (loc.getTime() == lastLoc.getTime()) {
1547 return false;
1548 }
1549
1550 // Check whether sufficient distance has been traveled
1551 double minDistance = record.mMinDistance;
1552 if (minDistance > 0.0) {
1553 if (loc.distanceTo(lastLoc) <= minDistance) {
1554 return false;
1555 }
1556 }
1557
1558 return true;
1559 }
1560
The Android Open Source Project3001a032009-02-19 10:57:31 -08001561 private void handleLocationChangedLocked(String provider) {
1562 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001563 if (records == null || records.size() == 0) {
1564 return;
1565 }
1566
1567 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
1568 if (p == null) {
1569 return;
1570 }
1571
1572 // Get location object
1573 Location loc = mLocationsByProvider.get(provider);
1574 if (loc == null) {
1575 loc = new Location(provider);
1576 mLocationsByProvider.put(provider, loc);
1577 } else {
1578 loc.reset();
1579 }
1580
1581 // Use the mock location if available
1582 Location mockLoc = mMockProviderLocation.get(provider);
1583 boolean locationValid;
1584 if (mockLoc != null) {
1585 locationValid = true;
1586 loc.set(mockLoc);
1587 } else {
1588 locationValid = p.getLocation(loc);
1589 }
1590
1591 // Update last known location for provider
1592 if (locationValid) {
1593 Location location = mLastKnownLocation.get(provider);
1594 if (location == null) {
1595 mLastKnownLocation.put(provider, new Location(loc));
1596 } else {
1597 location.set(loc);
1598 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001599 writeLastKnownLocationLocked(provider, loc);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001600
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001601 if (p instanceof INetworkLocationProvider) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001602 mWakeLockNetworkReceived = true;
1603 } else if (p instanceof GpsLocationProvider) {
1604 // Gps location received signal is in NetworkStateBroadcastReceiver
1605 }
1606 }
1607
1608 // Fetch latest status update time
1609 long newStatusUpdateTime = p.getStatusUpdateTime();
1610
1611 // Override real time with mock time if present
1612 Long mockStatusUpdateTime = mMockProviderStatusUpdateTime.get(provider);
1613 if (mockStatusUpdateTime != null) {
1614 newStatusUpdateTime = mockStatusUpdateTime.longValue();
1615 }
1616
1617 // Get latest status
1618 Bundle extras = new Bundle();
1619 int status = p.getStatus(extras);
1620
1621 // Override status with mock status if present
1622 Integer mockStatus = mMockProviderStatus.get(provider);
1623 if (mockStatus != null) {
1624 status = mockStatus.intValue();
1625 }
1626
1627 // Override extras with mock extras if present
1628 Bundle mockExtras = mMockProviderStatusExtras.get(provider);
1629 if (mockExtras != null) {
1630 extras.clear();
1631 extras.putAll(mockExtras);
1632 }
1633
The Android Open Source Project3001a032009-02-19 10:57:31 -08001634 ArrayList<Receiver> deadReceivers = null;
1635
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001636 // Broadcast location or status to all listeners
The Android Open Source Project3001a032009-02-19 10:57:31 -08001637 final int N = records.size();
1638 for (int i=0; i<N; i++) {
1639 UpdateRecord r = records.get(i);
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001640 Receiver receiver = r.mReceiver;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001641
1642 // Broadcast location only if it is valid
1643 if (locationValid) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001644 HashMap<String,Location> map = mLastFixBroadcast.get(receiver);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001645 if (map == null) {
1646 map = new HashMap<String,Location>();
The Android Open Source Project3001a032009-02-19 10:57:31 -08001647 mLastFixBroadcast.put(receiver, map);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001648 }
1649 Location lastLoc = map.get(provider);
The Android Open Source Project3001a032009-02-19 10:57:31 -08001650 if ((lastLoc == null) || shouldBroadcastSafe(loc, lastLoc, r)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001651 if (lastLoc == null) {
1652 lastLoc = new Location(loc);
1653 map.put(provider, lastLoc);
1654 } else {
1655 lastLoc.set(loc);
1656 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001657 if (!receiver.callLocationChangedLocked(loc)) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001658 Log.w(TAG, "RemoteException calling onLocationChanged on " + receiver);
The Android Open Source Project3001a032009-02-19 10:57:31 -08001659 if (deadReceivers == null) {
1660 deadReceivers = new ArrayList<Receiver>();
1661 }
1662 deadReceivers.add(receiver);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001663 }
1664 }
1665 }
1666
1667 // Broadcast status message
The Android Open Source Project3001a032009-02-19 10:57:31 -08001668 HashMap<String,Long> statusMap = mLastStatusBroadcast.get(receiver);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001669 if (statusMap == null) {
1670 statusMap = new HashMap<String,Long>();
The Android Open Source Project3001a032009-02-19 10:57:31 -08001671 mLastStatusBroadcast.put(receiver, statusMap);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001672 }
1673 long prevStatusUpdateTime =
1674 (statusMap.get(provider) != null) ? statusMap.get(provider) : 0;
1675
1676 if ((newStatusUpdateTime > prevStatusUpdateTime) &&
1677 (prevStatusUpdateTime != 0 || status != LocationProvider.AVAILABLE)) {
1678
1679 statusMap.put(provider, newStatusUpdateTime);
The Android Open Source Project3001a032009-02-19 10:57:31 -08001680 if (!receiver.callStatusChangedLocked(provider, status, extras)) {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001681 Log.w(TAG, "RemoteException calling onStatusChanged on " + receiver);
The Android Open Source Project3001a032009-02-19 10:57:31 -08001682 if (deadReceivers == null) {
1683 deadReceivers = new ArrayList<Receiver>();
1684 }
1685 if (!deadReceivers.contains(receiver)) {
1686 deadReceivers.add(receiver);
1687 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001688 }
1689 }
1690 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08001691
1692 if (deadReceivers != null) {
1693 for (int i=deadReceivers.size()-1; i>=0; i--) {
1694 removeUpdatesLocked(deadReceivers.get(i));
1695 }
1696 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001697 }
1698
1699 private class LocationWorkerHandler extends Handler {
1700
1701 @Override
1702 public void handleMessage(Message msg) {
1703 try {
1704 if (msg.what == MESSAGE_HEARTBEAT) {
1705 // log("LocationWorkerHandler: Heartbeat!");
1706
The Android Open Source Project3001a032009-02-19 10:57:31 -08001707 synchronized (mLocationListeners) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001708 String provider = (String) msg.obj;
The Android Open Source Project3001a032009-02-19 10:57:31 -08001709 if (!isAllowedBySettingsLocked(provider)) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001710 return;
1711 }
1712
1713 // Process the location fix if the screen is on or we're holding a wakelock
1714 if (mScreenOn || (mWakeLockAcquireTime != 0)) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001715 handleLocationChangedLocked(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001716 }
1717
1718 // If it continues to have listeners
The Android Open Source Project3001a032009-02-19 10:57:31 -08001719 ArrayList<UpdateRecord> records = mRecordsByProvider.get(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001720 if (records != null && records.size() > 0) {
1721 Message m = Message.obtain(this, MESSAGE_HEARTBEAT, provider);
1722 sendMessageAtTime(m, SystemClock.uptimeMillis() + 1000);
1723 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001724
The Android Open Source Project3001a032009-02-19 10:57:31 -08001725 if ((mWakeLockAcquireTime != 0) &&
1726 (SystemClock.elapsedRealtime() - mWakeLockAcquireTime
1727 > MAX_TIME_FOR_WAKE_LOCK)) {
1728
1729 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1730 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1731
1732 log("LocationWorkerHandler: Exceeded max time for wake lock");
1733 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1734 sendMessageAtFrontOfQueue(m);
1735
1736 } else if (mWakeLockAcquireTime != 0 &&
1737 mWakeLockGpsReceived && mWakeLockNetworkReceived) {
1738
1739 removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1740 removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
1741
1742 log("LocationWorkerHandler: Locations received.");
1743 mWakeLockAcquireTime = 0;
1744 Message m = Message.obtain(this, MESSAGE_RELEASE_WAKE_LOCK);
1745 sendMessageDelayed(m, TIME_AFTER_WAKE_LOCK);
1746 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001747 }
1748
1749 } else if (msg.what == MESSAGE_ACQUIRE_WAKE_LOCK) {
1750 log("LocationWorkerHandler: Acquire");
The Android Open Source Project3001a032009-02-19 10:57:31 -08001751 synchronized (mLocationListeners) {
1752 acquireWakeLockLocked();
1753 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001754 } else if (msg.what == MESSAGE_RELEASE_WAKE_LOCK) {
1755 log("LocationWorkerHandler: Release");
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001756
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001757 // Update wakelock status so the next alarm is set before releasing wakelock
The Android Open Source Project3001a032009-02-19 10:57:31 -08001758 synchronized (mLocationListeners) {
1759 updateWakelockStatusLocked(mScreenOn);
1760 releaseWakeLockLocked();
1761 }
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001762 } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001763 synchronized (mLocationListeners) {
The Android Open Source Projectda996f32009-02-13 12:57:50 -08001764 Log.d(TAG, "installing network location provider");
1765 INetworkLocationManager.InstallCallback callback =
1766 (INetworkLocationManager.InstallCallback)msg.obj;
The Android Open Source Project076357b2009-03-03 14:04:24 -08001767 callback.installNetworkLocationProvider(mContext, LocationManagerService.this);
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001768 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001769 }
1770 } catch (Exception e) {
1771 // Log, don't crash!
1772 Log.e(TAG, "Exception in LocationWorkerHandler.handleMessage:", e);
1773 }
1774 }
1775 }
1776
The Android Open Source Project3dec7d52009-03-02 22:54:33 -08001777 PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
1778
The Android Open Source Project076357b2009-03-03 14:04:24 -08001779 private CellState mLastCellState = null;
The Android Open Source Project3dec7d52009-03-02 22:54:33 -08001780 @Override
1781 public void onCellLocationChanged(CellLocation cellLocation) {
The Android Open Source Project076357b2009-03-03 14:04:24 -08001782 try {
1783 synchronized (mLocationListeners) {
1784 int asu = mSignalStrength;
1785
1786 // Gets cell state
1787 mLastCellState = new CellState(mTelephonyManager, cellLocation, asu);
1788
1789 // Notify collector
1790 if (mCollector != null) {
1791 mCollector.updateCellState(mLastCellState);
1792 }
1793
1794 // Updates providers
1795 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1796 for (LocationProviderImpl provider : providers) {
1797 if (provider.requiresCell()) {
1798 provider.updateCellState(mLastCellState);
1799 }
1800 }
The Android Open Source Project3dec7d52009-03-02 22:54:33 -08001801 }
The Android Open Source Project076357b2009-03-03 14:04:24 -08001802 } catch (Exception e) {
1803 Log.e(TAG, "Exception in PhoneStateListener.onCellLocationCahnged:", e);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001804 }
1805 }
1806
1807 @Override
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001808 public void onSignalStrengthChanged(int asu) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001809 synchronized (mLocationListeners) {
The Android Open Source Project076357b2009-03-03 14:04:24 -08001810 mSignalStrength = asu;
The Android Open Source Project3001a032009-02-19 10:57:31 -08001811
1812 if (mLastCellState != null) {
1813 mLastCellState.updateSignalStrength(asu);
1814 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001815 }
1816 }
1817
1818 @Override
1819 public void onDataConnectionStateChanged(int state) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001820 synchronized (mLocationListeners) {
1821 if (mLastCellState != null) {
The Android Open Source Project076357b2009-03-03 14:04:24 -08001822 mLastCellState.updateRadioType(mTelephonyManager);
The Android Open Source Project3001a032009-02-19 10:57:31 -08001823 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001824 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001825 }
1826 };
1827
1828 private class PowerStateBroadcastReceiver extends BroadcastReceiver {
1829 @Override public void onReceive(Context context, Intent intent) {
1830 String action = intent.getAction();
1831
1832 if (action.equals(ALARM_INTENT)) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08001833 synchronized (mLocationListeners) {
1834 log("PowerStateBroadcastReceiver: Alarm received");
1835 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
1836 // Have to do this immediately, rather than posting a
1837 // message, so we execute our code while the system
1838 // is holding a wake lock until the alarm broadcast
1839 // is finished.
1840 acquireWakeLockLocked();
1841 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001842
1843 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
1844 log("PowerStateBroadcastReceiver: Screen off");
The Android Open Source Project3001a032009-02-19 10:57:31 -08001845 synchronized (mLocationListeners) {
1846 updateWakelockStatusLocked(false);
1847 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001848
1849 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
1850 log("PowerStateBroadcastReceiver: Screen on");
The Android Open Source Project3001a032009-02-19 10:57:31 -08001851 synchronized (mLocationListeners) {
1852 updateWakelockStatusLocked(true);
1853 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001854
1855 } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
1856 log("PowerStateBroadcastReceiver: Battery changed");
The Android Open Source Project3001a032009-02-19 10:57:31 -08001857 synchronized (mLocationListeners) {
1858 int scale = intent.getIntExtra(BATTERY_EXTRA_SCALE, 100);
1859 int level = intent.getIntExtra(BATTERY_EXTRA_LEVEL, 0);
1860 boolean plugged = intent.getIntExtra(BATTERY_EXTRA_PLUGGED, 0) != 0;
1861
1862 // Notify collector battery state
1863 if (mCollector != null) {
1864 mCollector.updateBatteryState(scale, level, plugged);
1865 }
1866 }
1867 } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
1868 || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) {
1869 synchronized (mLocationListeners) {
1870 int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
1871 if (uid >= 0) {
1872 ArrayList<Receiver> removedRecs = null;
1873 for (ArrayList<UpdateRecord> i : mRecordsByProvider.values()) {
1874 for (int j=i.size()-1; j>=0; j--) {
1875 UpdateRecord ur = i.get(j);
1876 if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) {
1877 if (removedRecs == null) {
1878 removedRecs = new ArrayList<Receiver>();
1879 }
1880 if (!removedRecs.contains(ur.mReceiver)) {
1881 removedRecs.add(ur.mReceiver);
1882 }
1883 }
1884 }
1885 }
1886 ArrayList<ProximityAlert> removedAlerts = null;
1887 for (ProximityAlert i : mProximityAlerts.values()) {
1888 if (i.mUid == uid) {
1889 if (removedAlerts == null) {
1890 removedAlerts = new ArrayList<ProximityAlert>();
1891 }
1892 if (!removedAlerts.contains(i)) {
1893 removedAlerts.add(i);
1894 }
1895 }
1896 }
1897 if (removedRecs != null) {
1898 for (int i=removedRecs.size()-1; i>=0; i--) {
1899 removeUpdatesLocked(removedRecs.get(i));
1900 }
1901 }
1902 if (removedAlerts != null) {
1903 for (int i=removedAlerts.size()-1; i>=0; i--) {
1904 removeProximityAlertLocked(removedAlerts.get(i).mIntent);
1905 }
1906 }
1907 }
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08001908 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001909 }
1910 }
1911 }
1912
1913 private class NetworkStateBroadcastReceiver extends BroadcastReceiver {
1914 @Override public void onReceive(Context context, Intent intent) {
1915 String action = intent.getAction();
1916
1917 if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
1918
1919 List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
1920
1921 if (wifiScanResults == null) {
1922 return;
1923 }
1924
1925 // Notify provider and collector of Wifi scan results
The Android Open Source Project3001a032009-02-19 10:57:31 -08001926 synchronized (mLocationListeners) {
1927 if (mCollector != null) {
1928 mCollector.updateWifiScanResults(wifiScanResults);
1929 }
1930 if (mNetworkLocationInterface != null) {
1931 mNetworkLocationInterface.updateWifiScanResults(wifiScanResults);
1932 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001933 }
1934
1935 } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
1936 int networkState = LocationProvider.TEMPORARILY_UNAVAILABLE;
1937
1938 boolean noConnectivity =
1939 intent.getBooleanExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, false);
1940 if (!noConnectivity) {
1941 networkState = LocationProvider.AVAILABLE;
1942 }
1943
1944 // Notify location providers of current network state
The Android Open Source Project3001a032009-02-19 10:57:31 -08001945 synchronized (mLocationListeners) {
1946 List<LocationProviderImpl> providers = LocationProviderImpl.getProviders();
1947 for (LocationProviderImpl provider : providers) {
1948 if (provider.requiresNetwork()) {
1949 provider.updateNetworkState(networkState);
1950 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001951 }
1952 }
1953
1954 } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
1955 int state = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
1956 WifiManager.WIFI_STATE_UNKNOWN);
1957
1958 boolean enabled;
1959 if (state == WifiManager.WIFI_STATE_ENABLED) {
1960 enabled = true;
1961 } else if (state == WifiManager.WIFI_STATE_DISABLED) {
1962 enabled = false;
1963 } else {
1964 return;
1965 }
1966
1967 // Notify network provider of current wifi enabled state
The Android Open Source Project3001a032009-02-19 10:57:31 -08001968 synchronized (mLocationListeners) {
1969 if (mNetworkLocationInterface != null) {
1970 mNetworkLocationInterface.updateWifiEnabledState(enabled);
1971 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001972 }
1973
1974 } else if (action.equals(GpsLocationProvider.GPS_ENABLED_CHANGE_ACTION)) {
1975
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08001976 final boolean enabled = intent.getBooleanExtra(GpsLocationProvider.EXTRA_ENABLED,
1977 false);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001978
The Android Open Source Project3001a032009-02-19 10:57:31 -08001979 synchronized (mLocationListeners) {
1980 if (enabled) {
1981 updateReportedGpsLocked();
1982 mGpsNavigating = true;
1983 } else {
1984 reportStopGpsLocked();
1985 mGpsNavigating = false;
1986 // When GPS is disabled, we are OK to release wake-lock
1987 mWakeLockGpsReceived = true;
1988 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001989 }
1990 }
1991
1992 }
1993 }
1994
1995 // Wake locks
1996
The Android Open Source Project3001a032009-02-19 10:57:31 -08001997 private void updateWakelockStatusLocked(boolean screenOn) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07001998 log("updateWakelockStatus(): " + screenOn);
1999
2000 boolean needsLock = false;
2001 long minTime = Integer.MAX_VALUE;
2002
2003 if (mNetworkLocationProvider != null && mNetworkLocationProvider.isLocationTracking()) {
2004 needsLock = true;
2005 minTime = Math.min(mNetworkLocationProvider.getMinTime(), minTime);
2006 }
2007
2008 if (mGpsLocationProvider != null && mGpsLocationProvider.isLocationTracking()) {
2009 needsLock = true;
2010 minTime = Math.min(mGpsLocationProvider.getMinTime(), minTime);
2011 if (screenOn) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002012 startGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002013 } else if (mScreenOn && !screenOn) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002014 // We just turned the screen off so stop navigating
The Android Open Source Project3001a032009-02-19 10:57:31 -08002015 stopGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002016 }
2017 }
2018
2019 mScreenOn = screenOn;
2020
2021 PendingIntent sender =
2022 PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_INTENT), 0);
2023
2024 // Cancel existing alarm
2025 log("Cancelling existing alarm");
2026 mAlarmManager.cancel(sender);
2027
2028 if (needsLock && !mScreenOn) {
2029 long now = SystemClock.elapsedRealtime();
2030 mAlarmManager.set(
2031 AlarmManager.ELAPSED_REALTIME_WAKEUP, now + minTime, sender);
2032 mAlarmInterval = minTime;
2033 log("Creating a new wakelock alarm with minTime = " + minTime);
2034 } else {
2035 log("No need for alarm");
2036 mAlarmInterval = -1;
2037
2038 // Clear out existing wakelocks
2039 mLocationHandler.removeMessages(MESSAGE_ACQUIRE_WAKE_LOCK);
2040 mLocationHandler.removeMessages(MESSAGE_RELEASE_WAKE_LOCK);
The Android Open Source Project3001a032009-02-19 10:57:31 -08002041 releaseWakeLockLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002042 }
2043 }
2044
The Android Open Source Project3001a032009-02-19 10:57:31 -08002045 private void acquireWakeLockLocked() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002046 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002047 acquireWakeLockXLocked();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002048 } catch (Exception e) {
2049 // This is to catch a runtime exception thrown when we try to release an
2050 // already released lock.
2051 Log.e(TAG, "exception in acquireWakeLock()", e);
2052 }
2053 }
2054
The Android Open Source Project3001a032009-02-19 10:57:31 -08002055 private void acquireWakeLockXLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002056 if (mWakeLock.isHeld()) {
2057 log("Must release wakelock before acquiring");
2058 mWakeLockAcquireTime = 0;
2059 mWakeLock.release();
2060 }
2061
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002062 boolean networkActive = (mNetworkLocationProvider != null)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002063 && mNetworkLocationProvider.isLocationTracking();
2064 boolean gpsActive = (mGpsLocationProvider != null)
2065 && mGpsLocationProvider.isLocationTracking();
2066
2067 boolean needsLock = networkActive || gpsActive;
2068 if (!needsLock) {
2069 log("No need for Lock!");
2070 return;
2071 }
2072
2073 mWakeLockGpsReceived = !gpsActive;
2074 mWakeLockNetworkReceived = !networkActive;
2075
2076 // Acquire wake lock
2077 mWakeLock.acquire();
2078 mWakeLockAcquireTime = SystemClock.elapsedRealtime();
2079 log("Acquired wakelock");
2080
2081 // Start the gps provider
The Android Open Source Project3001a032009-02-19 10:57:31 -08002082 startGpsLocked();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002083
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002084 // Acquire cell lock
2085 if (mCellWakeLockAcquired) {
2086 // Lock is already acquired
2087 } else if (!mWakeLockNetworkReceived) {
2088 mTelephonyManager.enableLocationUpdates();
2089 mCellWakeLockAcquired = true;
2090 } else {
2091 mCellWakeLockAcquired = false;
2092 }
2093
2094 // Notify NetworkLocationProvider
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08002095 if (mNetworkLocationInterface != null) {
2096 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002097 }
2098
2099 // Acquire wifi lock
The Android Open Source Project3001a032009-02-19 10:57:31 -08002100 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002101 if (wifiLock != null) {
2102 if (mWifiWakeLockAcquired) {
2103 // Lock is already acquired
2104 } else if (mWifiManager.isWifiEnabled() && !mWakeLockNetworkReceived) {
2105 wifiLock.acquire();
2106 mWifiWakeLockAcquired = true;
2107 } else {
2108 mWifiWakeLockAcquired = false;
2109 Log.w(TAG, "acquireWakeLock(): Unable to get WiFi lock");
2110 }
2111 }
2112 }
2113
The Android Open Source Project3001a032009-02-19 10:57:31 -08002114 private boolean reportGpsUidLocked(int curSeq, int nextSeq, int uid) {
2115 int seq = mReportedGpsUids.get(uid, -1);
2116 if (seq == curSeq) {
2117 // Already reported; propagate to next sequence.
2118 mReportedGpsUids.put(uid, nextSeq);
2119 return true;
2120 } else if (seq != nextSeq) {
2121 try {
2122 // New UID; report it.
2123 mBatteryStats.noteStartGps(uid);
2124 mReportedGpsUids.put(uid, nextSeq);
2125 return true;
2126 } catch (RemoteException e) {
2127 }
2128 }
2129 return false;
2130 }
2131
2132 private void updateReportedGpsLocked() {
2133 if (mGpsLocationProvider == null) {
2134 return;
2135 }
2136
2137 final String name = mGpsLocationProvider.getName();
2138 final int curSeq = mReportedGpsSeq;
2139 final int nextSeq = (curSeq+1) >= 0 ? (curSeq+1) : 0;
2140 mReportedGpsSeq = nextSeq;
2141
2142 ArrayList<UpdateRecord> urs = mRecordsByProvider.get(name);
2143 int num = 0;
2144 final int N = urs.size();
2145 for (int i=0; i<N; i++) {
2146 UpdateRecord ur = urs.get(i);
2147 if (ur.mReceiver == mProximityListener) {
2148 // We don't want the system to take the blame for this one.
2149 continue;
2150 }
2151 if (reportGpsUidLocked(curSeq, nextSeq, ur.mUid)) {
2152 num++;
2153 }
2154 }
2155
2156 for (ProximityAlert pe : mProximityAlerts.values()) {
2157 if (reportGpsUidLocked(curSeq, nextSeq, pe.mUid)) {
2158 num++;
2159 }
2160 }
2161
2162 if (num != mReportedGpsUids.size()) {
2163 // The number of uids is processed is different than the
2164 // array; report any that are no longer active.
2165 for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
2166 if (mReportedGpsUids.valueAt(i) != nextSeq) {
2167 try {
2168 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
2169 } catch (RemoteException e) {
2170 }
2171 mReportedGpsUids.removeAt(i);
2172 }
2173 }
2174 }
2175 }
2176
2177 private void reportStopGpsLocked() {
2178 int curSeq = mReportedGpsSeq;
2179 for (int i=mReportedGpsUids.size()-1; i>=0; i--) {
2180 if (mReportedGpsUids.valueAt(i) == curSeq) {
2181 try {
2182 mBatteryStats.noteStopGps(mReportedGpsUids.keyAt(i));
2183 } catch (RemoteException e) {
2184 }
2185 }
2186 }
2187 curSeq++;
2188 if (curSeq < 0) curSeq = 0;
2189 mReportedGpsSeq = curSeq;
2190 mReportedGpsUids.clear();
2191 }
2192
2193 private void startGpsLocked() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002194 boolean gpsActive = (mGpsLocationProvider != null)
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002195 && mGpsLocationProvider.isLocationTracking();
2196 if (gpsActive) {
2197 mGpsLocationProvider.startNavigating();
2198 }
2199 }
2200
The Android Open Source Project3001a032009-02-19 10:57:31 -08002201 private void stopGpsLocked() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002202 boolean gpsActive = mGpsLocationProvider != null
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002203 && mGpsLocationProvider.isLocationTracking();
2204 if (gpsActive) {
2205 mGpsLocationProvider.stopNavigating();
2206 }
2207 }
2208
The Android Open Source Project3001a032009-02-19 10:57:31 -08002209 private void releaseWakeLockLocked() {
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002210 try {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002211 releaseWakeLockXLocked();
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002212 } catch (Exception e) {
2213 // This is to catch a runtime exception thrown when we try to release an
2214 // already released lock.
2215 Log.e(TAG, "exception in releaseWakeLock()", e);
2216 }
2217 }
2218
The Android Open Source Project3001a032009-02-19 10:57:31 -08002219 private void releaseWakeLockXLocked() {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002220 // Release wifi lock
The Android Open Source Project3001a032009-02-19 10:57:31 -08002221 WifiManager.WifiLock wifiLock = getWifiWakelockLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002222 if (wifiLock != null) {
2223 if (mWifiWakeLockAcquired) {
2224 wifiLock.release();
2225 mWifiWakeLockAcquired = false;
2226 }
2227 }
2228
2229 if (!mScreenOn) {
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002230 // Stop the gps
The Android Open Source Project3001a032009-02-19 10:57:31 -08002231 stopGpsLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002232 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002233
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002234 // Release cell lock
2235 if (mCellWakeLockAcquired) {
2236 mTelephonyManager.disableLocationUpdates();
2237 mCellWakeLockAcquired = false;
2238 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002239
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002240 // Notify NetworkLocationProvider
The Android Open Source Projectd24b8182009-02-10 15:44:00 -08002241 if (mNetworkLocationInterface != null) {
2242 mNetworkLocationInterface.updateCellLockStatus(mCellWakeLockAcquired);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002243 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002244
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002245 // Release wake lock
2246 mWakeLockAcquireTime = 0;
2247 if (mWakeLock.isHeld()) {
2248 log("Released wakelock");
2249 mWakeLock.release();
2250 } else {
2251 log("Can't release wakelock again!");
2252 }
2253 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002254
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002255 // Geocoder
2256
2257 public String getFromLocation(double latitude, double longitude, int maxResults,
2258 String language, String country, String variant, String appName, List<Address> addrs) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002259 synchronized (mLocationListeners) {
2260 if (mNetworkLocationInterface != null) {
2261 return mNetworkLocationInterface.getFromLocation(latitude, longitude, maxResults,
2262 language, country, variant, appName, addrs);
2263 } else {
2264 return null;
2265 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002266 }
2267 }
2268
2269 public String getFromLocationName(String locationName,
2270 double lowerLeftLatitude, double lowerLeftLongitude,
2271 double upperRightLatitude, double upperRightLongitude, int maxResults,
2272 String language, String country, String variant, String appName, List<Address> addrs) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002273 synchronized (mLocationListeners) {
2274 if (mNetworkLocationInterface != null) {
2275 return mNetworkLocationInterface.getFromLocationName(locationName, lowerLeftLatitude,
2276 lowerLeftLongitude, upperRightLatitude, upperRightLongitude, maxResults,
2277 language, country, variant, appName, addrs);
2278 } else {
2279 return null;
2280 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002281 }
2282 }
2283
2284 // Mock Providers
2285
2286 class MockProvider extends LocationProviderImpl {
2287 boolean mRequiresNetwork;
2288 boolean mRequiresSatellite;
2289 boolean mRequiresCell;
2290 boolean mHasMonetaryCost;
2291 boolean mSupportsAltitude;
2292 boolean mSupportsSpeed;
2293 boolean mSupportsBearing;
2294 int mPowerRequirement;
2295 int mAccuracy;
2296
2297 public MockProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
2298 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
2299 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
2300 super(name);
2301
2302 mRequiresNetwork = requiresNetwork;
2303 mRequiresSatellite = requiresSatellite;
2304 mRequiresCell = requiresCell;
2305 mHasMonetaryCost = hasMonetaryCost;
2306 mSupportsAltitude = supportsAltitude;
2307 mSupportsBearing = supportsBearing;
2308 mSupportsSpeed = supportsSpeed;
2309 mPowerRequirement = powerRequirement;
2310 mAccuracy = accuracy;
2311 }
2312
2313 @Override
2314 public void disable() {
2315 String name = getName();
The Android Open Source Project3001a032009-02-19 10:57:31 -08002316 // We shouldn't normally need to lock, since this should only be called
2317 // by the service with the lock held, but let's be paranid.
2318 synchronized (mLocationListeners) {
2319 mEnabledProviders.remove(name);
2320 mDisabledProviders.add(name);
2321 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002322 }
2323
2324 @Override
2325 public void enable() {
2326 String name = getName();
The Android Open Source Project3001a032009-02-19 10:57:31 -08002327 // We shouldn't normally need to lock, since this should only be called
2328 // by the service with the lock held, but let's be paranid.
2329 synchronized (mLocationListeners) {
2330 mEnabledProviders.add(name);
2331 mDisabledProviders.remove(name);
2332 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002333 }
2334
2335 @Override
2336 public boolean getLocation(Location l) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002337 // We shouldn't normally need to lock, since this should only be called
2338 // by the service with the lock held, but let's be paranid.
2339 synchronized (mLocationListeners) {
2340 Location loc = mMockProviderLocation.get(getName());
2341 if (loc == null) {
2342 return false;
2343 }
2344 l.set(loc);
2345 return true;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002346 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002347 }
2348
2349 @Override
2350 public int getStatus(Bundle extras) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002351 // We shouldn't normally need to lock, since this should only be called
2352 // by the service with the lock held, but let's be paranid.
2353 synchronized (mLocationListeners) {
2354 String name = getName();
2355 Integer s = mMockProviderStatus.get(name);
2356 int status = (s == null) ? AVAILABLE : s.intValue();
2357 Bundle newExtras = mMockProviderStatusExtras.get(name);
2358 if (newExtras != null) {
2359 extras.clear();
2360 extras.putAll(newExtras);
2361 }
2362 return status;
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002363 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002364 }
2365
2366 @Override
2367 public boolean isEnabled() {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002368 // We shouldn't normally need to lock, since this should only be called
2369 // by the service with the lock held, but let's be paranid.
2370 synchronized (mLocationListeners) {
2371 return mEnabledProviders.contains(getName());
2372 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002373 }
2374
2375 @Override
2376 public int getAccuracy() {
2377 return mAccuracy;
2378 }
2379
2380 @Override
2381 public int getPowerRequirement() {
2382 return mPowerRequirement;
2383 }
2384
2385 @Override
2386 public boolean hasMonetaryCost() {
2387 return mHasMonetaryCost;
2388 }
2389
2390 @Override
2391 public boolean requiresCell() {
2392 return mRequiresCell;
2393 }
2394
2395 @Override
2396 public boolean requiresNetwork() {
2397 return mRequiresNetwork;
2398 }
2399
2400 @Override
2401 public boolean requiresSatellite() {
2402 return mRequiresSatellite;
2403 }
2404
2405 @Override
2406 public boolean supportsAltitude() {
2407 return mSupportsAltitude;
2408 }
2409
2410 @Override
2411 public boolean supportsBearing() {
2412 return mSupportsBearing;
2413 }
2414
2415 @Override
2416 public boolean supportsSpeed() {
2417 return mSupportsSpeed;
2418 }
2419 }
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002420
The Android Open Source Project3001a032009-02-19 10:57:31 -08002421 private void checkMockPermissionsSafe() {
2422 boolean allowMocks = Settings.Secure.getInt(mContext.getContentResolver(),
2423 Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 1;
The Android Open Source Projectf013e1a2008-12-17 18:05:43 -08002424 if (!allowMocks) {
2425 throw new SecurityException("Requires ACCESS_MOCK_LOCATION secure setting");
2426 }
2427
2428 if (mContext.checkCallingPermission(ACCESS_MOCK_LOCATION) !=
2429 PackageManager.PERMISSION_GRANTED) {
2430 throw new SecurityException("Requires ACCESS_MOCK_LOCATION permission");
2431 }
2432 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002433
2434 public void addTestProvider(String name, boolean requiresNetwork, boolean requiresSatellite,
2435 boolean requiresCell, boolean hasMonetaryCost, boolean supportsAltitude,
2436 boolean supportsSpeed, boolean supportsBearing, int powerRequirement, int accuracy) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002437 checkMockPermissionsSafe();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002438
The Android Open Source Project3001a032009-02-19 10:57:31 -08002439 synchronized (mLocationListeners) {
2440 MockProvider provider = new MockProvider(name, requiresNetwork, requiresSatellite,
2441 requiresCell, hasMonetaryCost, supportsAltitude,
2442 supportsSpeed, supportsBearing, powerRequirement, accuracy);
2443 if (LocationProviderImpl.getProvider(name) != null) {
2444 throw new IllegalArgumentException("Provider \"" + name + "\" already exists");
2445 }
2446 LocationProviderImpl.addProvider(provider);
2447 updateProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002448 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002449 }
2450
2451 public void removeTestProvider(String provider) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002452 checkMockPermissionsSafe();
2453 synchronized (mLocationListeners) {
2454 LocationProviderImpl p = LocationProviderImpl.getProvider(provider);
2455 if (p == null) {
2456 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2457 }
2458 LocationProviderImpl.removeProvider(p);
2459 updateProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002460 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002461 }
2462
2463 public void setTestProviderLocation(String provider, Location loc) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002464 checkMockPermissionsSafe();
2465 synchronized (mLocationListeners) {
2466 if (LocationProviderImpl.getProvider(provider) == null) {
2467 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2468 }
2469 mMockProviderLocation.put(provider, loc);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002470 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002471 }
2472
2473 public void clearTestProviderLocation(String provider) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002474 checkMockPermissionsSafe();
2475 synchronized (mLocationListeners) {
2476 if (LocationProviderImpl.getProvider(provider) == null) {
2477 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2478 }
2479 mMockProviderLocation.remove(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002480 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002481 }
2482
2483 public void setTestProviderEnabled(String provider, boolean enabled) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002484 checkMockPermissionsSafe();
2485 synchronized (mLocationListeners) {
2486 if (LocationProviderImpl.getProvider(provider) == null) {
2487 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2488 }
2489 if (enabled) {
2490 mEnabledProviders.add(provider);
2491 mDisabledProviders.remove(provider);
2492 } else {
2493 mEnabledProviders.remove(provider);
2494 mDisabledProviders.add(provider);
2495 }
2496 updateProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002497 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002498 }
2499
2500 public void clearTestProviderEnabled(String provider) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002501 checkMockPermissionsSafe();
2502 synchronized (mLocationListeners) {
2503 if (LocationProviderImpl.getProvider(provider) == null) {
2504 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2505 }
2506 mEnabledProviders.remove(provider);
2507 mDisabledProviders.remove(provider);
2508 updateProvidersLocked();
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002509 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002510 }
2511
2512 public void setTestProviderStatus(String provider, int status, Bundle extras, long updateTime) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002513 checkMockPermissionsSafe();
2514 synchronized (mLocationListeners) {
2515 if (LocationProviderImpl.getProvider(provider) == null) {
2516 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2517 }
2518 mMockProviderStatus.put(provider, new Integer(status));
2519 mMockProviderStatusExtras.put(provider, extras);
2520 mMockProviderStatusUpdateTime.put(provider, new Long(updateTime));
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002521 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002522 }
2523
2524 public void clearTestProviderStatus(String provider) {
The Android Open Source Project3001a032009-02-19 10:57:31 -08002525 checkMockPermissionsSafe();
2526 synchronized (mLocationListeners) {
2527 if (LocationProviderImpl.getProvider(provider) == null) {
2528 throw new IllegalArgumentException("Provider \"" + provider + "\" unknown");
2529 }
2530 mMockProviderStatus.remove(provider);
2531 mMockProviderStatusExtras.remove(provider);
2532 mMockProviderStatusUpdateTime.remove(provider);
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002533 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002534 }
2535
2536 private void log(String log) {
2537 if (Log.isLoggable(TAG, Log.VERBOSE)) {
2538 Log.d(TAG, log);
2539 }
2540 }
The Android Open Source Project3001a032009-02-19 10:57:31 -08002541
2542 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2543 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
2544 != PackageManager.PERMISSION_GRANTED) {
2545 pw.println("Permission Denial: can't dump AlarmManager from from pid="
2546 + Binder.getCallingPid()
2547 + ", uid=" + Binder.getCallingUid());
2548 return;
2549 }
2550
2551 synchronized (mLocationListeners) {
2552 pw.println("Current Location Manager state:");
2553 pw.println(" sProvidersLoaded=" + sProvidersLoaded);
2554 pw.println(" mGpsLocationProvider=" + mGpsLocationProvider);
2555 pw.println(" mGpsNavigating=" + mGpsNavigating);
2556 pw.println(" mNetworkLocationProvider=" + mNetworkLocationProvider);
2557 pw.println(" mNetworkLocationInterface=" + mNetworkLocationInterface);
2558 pw.println(" mCollector=" + mCollector);
The Android Open Source Project076357b2009-03-03 14:04:24 -08002559 pw.println(" mSignalStrength=" + mSignalStrength);
The Android Open Source Project3001a032009-02-19 10:57:31 -08002560 pw.println(" mAlarmInterval=" + mAlarmInterval
2561 + " mScreenOn=" + mScreenOn
2562 + " mWakeLockAcquireTime=" + mWakeLockAcquireTime);
2563 pw.println(" mWakeLockGpsReceived=" + mWakeLockGpsReceived
2564 + " mWakeLockNetworkReceived=" + mWakeLockNetworkReceived);
2565 pw.println(" mWifiWakeLockAcquired=" + mWifiWakeLockAcquired
2566 + " mCellWakeLockAcquired=" + mCellWakeLockAcquired);
2567 pw.println(" Listeners:");
2568 int N = mListeners.size();
2569 for (int i=0; i<N; i++) {
2570 pw.println(" " + mListeners.get(i));
2571 }
2572 pw.println(" Location Listeners:");
2573 for (Map.Entry<Receiver, HashMap<String,UpdateRecord>> i
2574 : mLocationListeners.entrySet()) {
2575 pw.println(" " + i.getKey() + ":");
2576 for (Map.Entry<String,UpdateRecord> j : i.getValue().entrySet()) {
2577 pw.println(" " + j.getKey() + ":");
2578 j.getValue().dump(pw, " ");
2579 }
2580 }
2581 pw.println(" Last Fix Broadcasts:");
2582 for (Map.Entry<Receiver, HashMap<String,Location>> i
2583 : mLastFixBroadcast.entrySet()) {
2584 pw.println(" " + i.getKey() + ":");
2585 for (Map.Entry<String,Location> j : i.getValue().entrySet()) {
2586 pw.println(" " + j.getKey() + ":");
2587 j.getValue().dump(new PrintWriterPrinter(pw), " ");
2588 }
2589 }
2590 pw.println(" Last Status Broadcasts:");
2591 for (Map.Entry<Receiver, HashMap<String,Long>> i
2592 : mLastStatusBroadcast.entrySet()) {
2593 pw.println(" " + i.getKey() + ":");
2594 for (Map.Entry<String,Long> j : i.getValue().entrySet()) {
2595 pw.println(" " + j.getKey() + " -> 0x"
2596 + Long.toHexString(j.getValue()));
2597 }
2598 }
2599 pw.println(" Records by Provider:");
2600 for (Map.Entry<String, ArrayList<UpdateRecord>> i
2601 : mRecordsByProvider.entrySet()) {
2602 pw.println(" " + i.getKey() + ":");
2603 for (UpdateRecord j : i.getValue()) {
2604 pw.println(" " + j + ":");
2605 j.dump(pw, " ");
2606 }
2607 }
2608 pw.println(" Locations by Provider:");
2609 for (Map.Entry<String, Location> i
2610 : mLocationsByProvider.entrySet()) {
2611 pw.println(" " + i.getKey() + ":");
2612 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2613 }
2614 pw.println(" Last Known Locations:");
2615 for (Map.Entry<String, Location> i
2616 : mLastKnownLocation.entrySet()) {
2617 pw.println(" " + i.getKey() + ":");
2618 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2619 }
2620 if (mProximityAlerts.size() > 0) {
2621 pw.println(" Proximity Alerts:");
2622 for (Map.Entry<PendingIntent, ProximityAlert> i
2623 : mProximityAlerts.entrySet()) {
2624 pw.println(" " + i.getKey() + ":");
2625 i.getValue().dump(pw, " ");
2626 }
2627 }
2628 if (mProximitiesEntered.size() > 0) {
2629 pw.println(" Proximities Entered:");
2630 for (ProximityAlert i : mProximitiesEntered) {
2631 pw.println(" " + i + ":");
2632 i.dump(pw, " ");
2633 }
2634 }
2635 pw.println(" mProximityListener=" + mProximityListener);
2636 if (mEnabledProviders.size() > 0) {
2637 pw.println(" Enabled Providers:");
2638 for (String i : mEnabledProviders) {
2639 pw.println(" " + i);
2640 }
2641
2642 }
2643 if (mDisabledProviders.size() > 0) {
2644 pw.println(" Disabled Providers:");
2645 for (String i : mDisabledProviders) {
2646 pw.println(" " + i);
2647 }
2648
2649 }
2650 if (mMockProviders.size() > 0) {
2651 pw.println(" Mock Providers:");
2652 for (Map.Entry<String, MockProvider> i : mMockProviders.entrySet()) {
2653 pw.println(" " + i.getKey() + " -> " + i.getValue());
2654 }
2655 }
2656 if (mMockProviderLocation.size() > 0) {
2657 pw.println(" Mock Provider Location:");
2658 for (Map.Entry<String, Location> i : mMockProviderLocation.entrySet()) {
2659 pw.println(" " + i.getKey() + ":");
2660 i.getValue().dump(new PrintWriterPrinter(pw), " ");
2661 }
2662 }
2663 if (mMockProviderStatus.size() > 0) {
2664 pw.println(" Mock Provider Status:");
2665 for (Map.Entry<String, Integer> i : mMockProviderStatus.entrySet()) {
2666 pw.println(" " + i.getKey() + " -> 0x"
2667 + Integer.toHexString(i.getValue()));
2668 }
2669 }
2670 if (mMockProviderStatusExtras.size() > 0) {
2671 pw.println(" Mock Provider Status Extras:");
2672 for (Map.Entry<String, Bundle> i : mMockProviderStatusExtras.entrySet()) {
2673 pw.println(" " + i.getKey() + " -> " + i.getValue());
2674 }
2675 }
2676 if (mMockProviderStatusUpdateTime.size() > 0) {
2677 pw.println(" Mock Provider Status Update Time:");
2678 for (Map.Entry<String, Long> i : mMockProviderStatusUpdateTime.entrySet()) {
2679 pw.println(" " + i.getKey() + " -> " + i.getValue());
2680 }
2681 }
2682 pw.println(" Reported GPS UIDs @ seq " + mReportedGpsSeq + ":");
2683 N = mReportedGpsUids.size();
2684 for (int i=0; i<N; i++) {
2685 pw.println(" UID " + mReportedGpsUids.keyAt(i)
2686 + " seq=" + mReportedGpsUids.valueAt(i));
2687 }
2688 }
2689 }
The Android Open Source Project54b6cfa2008-10-21 07:00:00 -07002690}
2691