2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.location;
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.location.Criteria;
26 import android.location.IGpsStatusListener;
27 import android.location.IGpsStatusProvider;
28 import android.location.ILocationManager;
29 import android.location.INetInitiatedListener;
30 import android.location.Location;
31 import android.location.LocationManager;
32 import android.location.LocationProvider;
33 import android.net.ConnectivityManager;
34 import android.net.NetworkInfo;
35 import android.net.SntpClient;
36 import android.os.Binder;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.IBinder;
40 import android.os.Looper;
41 import android.os.Message;
42 import android.os.PowerManager;
43 import android.os.Process;
44 import android.os.RemoteException;
45 import android.os.ServiceManager;
46 import android.os.SystemClock;
47 import android.os.WorkSource;
48 import android.provider.Settings;
49 import android.provider.Telephony.Sms.Intents;
50 import android.telephony.TelephonyManager;
51 import android.telephony.gsm.GsmCellLocation;
52 import android.telephony.SmsMessage;
53 import android.util.Log;
54 import android.util.SparseIntArray;
56 import com.android.internal.app.IBatteryStats;
57 import com.android.internal.telephony.Phone;
58 import com.android.internal.location.GpsNetInitiatedHandler;
59 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
60 import com.android.internal.telephony.GsmAlphabet;
61 import com.android.internal.telephony.SmsHeader;
62 import com.android.internal.util.HexDump;
65 import java.io.FileInputStream;
66 import java.io.IOException;
67 import java.io.StringBufferInputStream;
68 import java.net.InetAddress;
69 import java.net.UnknownHostException;
70 import java.util.ArrayList;
71 import java.util.Date;
72 import java.util.Properties;
73 import java.util.Map.Entry;
74 import java.util.concurrent.CountDownLatch;
77 * A GPS implementation of LocationProvider used by LocationManager.
81 public class GpsLocationProvider implements LocationProviderInterface {
83 private static final String TAG = "GpsLocationProvider";
85 private static final boolean DEBUG = true;
86 private static final boolean VERBOSE = false;
88 // these need to match GpsPositionMode enum in gps.h
89 private static final int GPS_POSITION_MODE_STANDALONE = 0;
90 private static final int GPS_POSITION_MODE_MS_BASED = 1;
91 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
93 // these need to match GpsPositionRecurrence enum in gps.h
94 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
95 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
97 // these need to match GpsStatusValue defines in gps.h
98 private static final int GPS_STATUS_NONE = 0;
99 private static final int GPS_STATUS_SESSION_BEGIN = 1;
100 private static final int GPS_STATUS_SESSION_END = 2;
101 private static final int GPS_STATUS_ENGINE_ON = 3;
102 private static final int GPS_STATUS_ENGINE_OFF = 4;
104 // these need to match GpsApgsStatusValue defines in gps.h
105 /** AGPS status event values. */
106 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
107 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
108 private static final int GPS_AGPS_DATA_CONNECTED = 3;
109 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
110 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
112 // these need to match GpsLocationFlags enum in gps.h
113 private static final int LOCATION_INVALID = 0;
114 private static final int LOCATION_HAS_LAT_LONG = 1;
115 private static final int LOCATION_HAS_ALTITUDE = 2;
116 private static final int LOCATION_HAS_SPEED = 4;
117 private static final int LOCATION_HAS_BEARING = 8;
118 private static final int LOCATION_HAS_ACCURACY = 16;
120 // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
121 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
122 private static final int GPS_DELETE_ALMANAC = 0x0002;
123 private static final int GPS_DELETE_POSITION = 0x0004;
124 private static final int GPS_DELETE_TIME = 0x0008;
125 private static final int GPS_DELETE_IONO = 0x0010;
126 private static final int GPS_DELETE_UTC = 0x0020;
127 private static final int GPS_DELETE_HEALTH = 0x0040;
128 private static final int GPS_DELETE_SVDIR = 0x0080;
129 private static final int GPS_DELETE_SVSTEER = 0x0100;
130 private static final int GPS_DELETE_SADATA = 0x0200;
131 private static final int GPS_DELETE_RTI = 0x0400;
132 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
133 private static final int GPS_DELETE_ALL = 0xFFFF;
135 // The GPS_CAPABILITY_* flags must match the values in gps.h
136 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
137 private static final int GPS_CAPABILITY_MSB = 0x0000002;
138 private static final int GPS_CAPABILITY_MSA = 0x0000004;
139 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
142 // these need to match AGpsType enum in gps.h
143 private static final int AGPS_TYPE_SUPL = 1;
144 private static final int AGPS_TYPE_C2K = 2;
146 // for mAGpsDataConnectionState
147 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
148 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
149 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
152 private static final int CHECK_LOCATION = 1;
153 private static final int ENABLE = 2;
154 private static final int ENABLE_TRACKING = 3;
155 private static final int UPDATE_NETWORK_STATE = 4;
156 private static final int INJECT_NTP_TIME = 5;
157 private static final int DOWNLOAD_XTRA_DATA = 6;
158 private static final int UPDATE_LOCATION = 7;
159 private static final int ADD_LISTENER = 8;
160 private static final int REMOVE_LISTENER = 9;
161 private static final int REQUEST_SINGLE_SHOT = 10;
164 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
165 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
167 // Request ref location
168 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
169 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
171 // ref. location info
172 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
173 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
174 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
177 private static final int AGPS_SETID_TYPE_NONE = 0;
178 private static final int AGPS_SETID_TYPE_IMSI = 1;
179 private static final int AGPS_SETID_TYPE_MSISDN = 2;
181 private static final String PROPERTIES_FILE = "/etc/gps.conf";
183 private int mLocationFlags = LOCATION_INVALID;
186 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
188 // time for last status update
189 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
191 // turn off GPS fix icon if we haven't received a fix in 10 seconds
192 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
194 // stop trying if we do not receive a fix within 60 seconds
195 private static final int NO_FIX_TIMEOUT = 60 * 1000;
197 // true if we are enabled
198 private volatile boolean mEnabled;
200 // true if we have network connectivity
201 private boolean mNetworkAvailable;
203 // flags to trigger NTP or XTRA data download when network becomes available
204 // initialized to true so we do NTP and XTRA when the network comes up after booting
205 private boolean mInjectNtpTimePending = true;
206 private boolean mDownloadXtraDataPending = false;
208 // true if GPS is navigating
209 private boolean mNavigating;
211 // true if GPS engine is on
212 private boolean mEngineOn;
214 // requested frequency of fixes, in milliseconds
215 private int mFixInterval = 1000;
217 // true if we started navigation
218 private boolean mStarted;
220 // true if single shot request is in progress
221 private boolean mSingleShot;
223 // capabilities of the GPS engine
224 private int mEngineCapabilities;
226 // true if XTRA is supported
227 private boolean mSupportsXtra;
229 // for calculating time to first fix
230 private long mFixRequestTime = 0;
231 // time to first fix for most recent session
232 private int mTTFF = 0;
233 // time we received our last fix
234 private long mLastFixTime;
236 private int mPositionMode;
238 // properties loaded from PROPERTIES_FILE
239 private Properties mProperties;
240 private String mNtpServer;
241 private String mSuplServerHost;
242 private int mSuplServerPort;
243 private String mC2KServerHost;
244 private int mC2KServerPort;
246 private final Context mContext;
247 private final ILocationManager mLocationManager;
248 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
249 private Bundle mLocationExtras = new Bundle();
250 private ArrayList<Listener> mListeners = new ArrayList<Listener>();
252 // GpsLocationProvider's handler thread
253 private final Thread mThread;
254 // Handler for processing events in mThread.
255 private Handler mHandler;
256 // Used to signal when our main thread has initialized everything
257 private final CountDownLatch mInitializedLatch = new CountDownLatch(1);
259 private String mAGpsApn;
260 private int mAGpsDataConnectionState;
261 private final ConnectivityManager mConnMgr;
262 private final GpsNetInitiatedHandler mNIHandler;
265 private final static String WAKELOCK_KEY = "GpsLocationProvider";
266 private final PowerManager.WakeLock mWakeLock;
267 // bitfield of pending messages to our Handler
268 // used only for messages that cannot have multiple instances queued
269 private int mPendingMessageBits;
270 // separate counter for ADD_LISTENER and REMOVE_LISTENER messages,
271 // which might have multiple instances queued
272 private int mPendingListenerMessages;
275 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
276 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
277 private final AlarmManager mAlarmManager;
278 private final PendingIntent mWakeupIntent;
279 private final PendingIntent mTimeoutIntent;
281 private final IBatteryStats mBatteryStats;
282 private final SparseIntArray mClientUids = new SparseIntArray();
284 // how often to request NTP time, in milliseconds
285 // current setting 4 hours
286 private static final long NTP_INTERVAL = 4*60*60*1000;
287 // how long to wait if we have a network error in NTP or XTRA downloading
288 // current setting - 5 minutes
289 private static final long RETRY_INTERVAL = 5*60*1000;
291 // to avoid injecting bad NTP time, we reject any time fixes that differ from system time
292 // by more than 5 minutes.
293 private static final long MAX_NTP_SYSTEM_TIME_OFFSET = 5*60*1000;
295 private final IGpsStatusProvider mGpsStatusProvider = new IGpsStatusProvider.Stub() {
296 public void addGpsStatusListener(IGpsStatusListener listener) throws RemoteException {
297 if (listener == null) {
298 throw new NullPointerException("listener is null in addGpsStatusListener");
301 synchronized(mListeners) {
302 IBinder binder = listener.asBinder();
303 int size = mListeners.size();
304 for (int i = 0; i < size; i++) {
305 Listener test = mListeners.get(i);
306 if (binder.equals(test.mListener.asBinder())) {
307 // listener already added
312 Listener l = new Listener(listener);
313 binder.linkToDeath(l, 0);
318 public void removeGpsStatusListener(IGpsStatusListener listener) {
319 if (listener == null) {
320 throw new NullPointerException("listener is null in addGpsStatusListener");
323 synchronized(mListeners) {
324 IBinder binder = listener.asBinder();
326 int size = mListeners.size();
327 for (int i = 0; i < size && l == null; i++) {
328 Listener test = mListeners.get(i);
329 if (binder.equals(test.mListener.asBinder())) {
335 mListeners.remove(l);
336 binder.unlinkToDeath(l, 0);
342 public IGpsStatusProvider getGpsStatusProvider() {
343 return mGpsStatusProvider;
346 private final BroadcastReceiver mBroadcastReciever = new BroadcastReceiver() {
347 @Override public void onReceive(Context context, Intent intent) {
348 String action = intent.getAction();
350 if (action.equals(ALARM_WAKEUP)) {
351 if (DEBUG) Log.d(TAG, "ALARM_WAKEUP");
352 startNavigating(false);
353 } else if (action.equals(ALARM_TIMEOUT)) {
354 if (DEBUG) Log.d(TAG, "ALARM_TIMEOUT");
356 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
357 checkSmsSuplInit(intent);
358 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
359 checkWapSuplInit(intent);
364 private void checkSmsSuplInit(Intent intent) {
365 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
366 for (int i=0; i <messages.length; i++) {
367 byte[] supl_init = messages[i].getUserData();
368 native_agps_ni_message(supl_init,supl_init.length);
372 private void checkWapSuplInit(Intent intent) {
373 byte[] supl_init = (byte[]) intent.getExtra("data");
374 native_agps_ni_message(supl_init,supl_init.length);
377 public static boolean isSupported() {
378 return native_is_supported();
381 public GpsLocationProvider(Context context, ILocationManager locationManager) {
383 mLocationManager = locationManager;
384 mNIHandler = new GpsNetInitiatedHandler(context);
386 mLocation.setExtras(mLocationExtras);
388 // Create a wake lock
389 PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
390 mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
391 mWakeLock.setReferenceCounted(false);
393 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
394 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
395 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
397 IntentFilter intentFilter = new IntentFilter();
398 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
399 intentFilter.addDataScheme("sms");
400 intentFilter.addDataAuthority("localhost","7275");
401 context.registerReceiver(mBroadcastReciever, intentFilter);
403 intentFilter = new IntentFilter();
404 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
406 intentFilter.addDataType("application/vnd.omaloc-supl-init");
407 } catch (IntentFilter.MalformedMimeTypeException e) {
408 Log.w(TAG, "Malformed SUPL init mime type");
410 context.registerReceiver(mBroadcastReciever, intentFilter);
412 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
414 // Battery statistics service to be notified when GPS turns on or off
415 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService("batteryinfo"));
417 mProperties = new Properties();
419 File file = new File(PROPERTIES_FILE);
420 FileInputStream stream = new FileInputStream(file);
421 mProperties.load(stream);
423 mNtpServer = mProperties.getProperty("NTP_SERVER", null);
425 mSuplServerHost = mProperties.getProperty("SUPL_HOST");
426 String portString = mProperties.getProperty("SUPL_PORT");
427 if (mSuplServerHost != null && portString != null) {
429 mSuplServerPort = Integer.parseInt(portString);
430 } catch (NumberFormatException e) {
431 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
435 mC2KServerHost = mProperties.getProperty("C2K_HOST");
436 portString = mProperties.getProperty("C2K_PORT");
437 if (mC2KServerHost != null && portString != null) {
439 mC2KServerPort = Integer.parseInt(portString);
440 } catch (NumberFormatException e) {
441 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
444 } catch (IOException e) {
445 Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
448 // wait until we are fully initialized before returning
449 mThread = new GpsLocationProviderThread();
453 mInitializedLatch.await();
455 } catch (InterruptedException e) {
456 Thread.currentThread().interrupt();
461 private void initialize() {
462 // register our receiver on our thread rather than the main thread
463 IntentFilter intentFilter = new IntentFilter();
464 intentFilter.addAction(ALARM_WAKEUP);
465 intentFilter.addAction(ALARM_TIMEOUT);
466 mContext.registerReceiver(mBroadcastReciever, intentFilter);
470 * Returns the name of this provider.
472 public String getName() {
473 return LocationManager.GPS_PROVIDER;
477 * Returns true if the provider requires access to a
478 * data network (e.g., the Internet), false otherwise.
480 public boolean requiresNetwork() {
484 public void updateNetworkState(int state, NetworkInfo info) {
485 sendMessage(UPDATE_NETWORK_STATE, state, info);
488 private void handleUpdateNetworkState(int state, NetworkInfo info) {
489 mNetworkAvailable = (state == LocationProvider.AVAILABLE);
492 Log.d(TAG, "updateNetworkState " + (mNetworkAvailable ? "available" : "unavailable")
497 native_update_network_state(info.isConnected(), info.getType(),
498 info.isRoaming(), info.getExtraInfo());
501 if (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE_SUPL
502 && mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
503 String apnName = info.getExtraInfo();
504 if (mNetworkAvailable && apnName != null && apnName.length() > 0) {
506 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_open");
507 native_agps_data_conn_open(apnName);
508 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
510 if (DEBUG) Log.d(TAG, "call native_agps_data_conn_failed");
512 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
513 native_agps_data_conn_failed();
517 if (mNetworkAvailable) {
518 if (mInjectNtpTimePending) {
519 sendMessage(INJECT_NTP_TIME, 0, null);
521 if (mDownloadXtraDataPending) {
522 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
527 private void handleInjectNtpTime() {
528 if (!mNetworkAvailable) {
529 // try again when network is up
530 mInjectNtpTimePending = true;
533 mInjectNtpTimePending = false;
535 SntpClient client = new SntpClient();
538 if (client.requestTime(mNtpServer, 10000)) {
539 long time = client.getNtpTime();
540 long timeReference = client.getNtpTimeReference();
541 int certainty = (int)(client.getRoundTripTime()/2);
542 long now = System.currentTimeMillis();
544 Log.d(TAG, "NTP server returned: "
545 + time + " (" + new Date(time)
546 + ") reference: " + timeReference
547 + " certainty: " + certainty
548 + " system time offset: " + (time - now));
550 native_inject_time(time, timeReference, certainty);
551 delay = NTP_INTERVAL;
553 if (DEBUG) Log.d(TAG, "requestTime failed");
554 delay = RETRY_INTERVAL;
557 // send delayed message for next NTP injection
558 // since this is delayed and not urgent we do not hold a wake lock here
559 mHandler.removeMessages(INJECT_NTP_TIME);
560 mHandler.sendMessageDelayed(Message.obtain(mHandler, INJECT_NTP_TIME), delay);
563 private void handleDownloadXtraData() {
564 if (!mNetworkAvailable) {
565 // try again when network is up
566 mDownloadXtraDataPending = true;
569 mDownloadXtraDataPending = false;
572 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mContext, mProperties);
573 byte[] data = xtraDownloader.downloadXtraData();
576 Log.d(TAG, "calling native_inject_xtra_data");
578 native_inject_xtra_data(data, data.length);
581 // since this is delayed and not urgent we do not hold a wake lock here
582 mHandler.removeMessages(DOWNLOAD_XTRA_DATA);
583 mHandler.sendMessageDelayed(Message.obtain(mHandler, DOWNLOAD_XTRA_DATA), RETRY_INTERVAL);
588 * This is called to inform us when another location provider returns a location.
589 * Someday we might use this for network location injection to aid the GPS
591 public void updateLocation(Location location) {
592 sendMessage(UPDATE_LOCATION, 0, location);
595 private void handleUpdateLocation(Location location) {
596 if (location.hasAccuracy()) {
597 native_inject_location(location.getLatitude(), location.getLongitude(),
598 location.getAccuracy());
603 * Returns true if the provider requires access to a
604 * satellite-based positioning system (e.g., GPS), false
607 public boolean requiresSatellite() {
612 * Returns true if the provider requires access to an appropriate
613 * cellular network (e.g., to make use of cell tower IDs), false
616 public boolean requiresCell() {
621 * Returns true if the use of this provider may result in a
622 * monetary charge to the user, false if use is free. It is up to
623 * each provider to give accurate information.
625 public boolean hasMonetaryCost() {
630 * Returns true if the provider is able to provide altitude
631 * information, false otherwise. A provider that reports altitude
632 * under most circumstances but may occassionally not report it
633 * should return true.
635 public boolean supportsAltitude() {
640 * Returns true if the provider is able to provide speed
641 * information, false otherwise. A provider that reports speed
642 * under most circumstances but may occassionally not report it
643 * should return true.
645 public boolean supportsSpeed() {
650 * Returns true if the provider is able to provide bearing
651 * information, false otherwise. A provider that reports bearing
652 * under most circumstances but may occassionally not report it
653 * should return true.
655 public boolean supportsBearing() {
660 * Returns the power requirement for this provider.
662 * @return the power requirement for this provider, as one of the
663 * constants Criteria.POWER_REQUIREMENT_*.
665 public int getPowerRequirement() {
666 return Criteria.POWER_HIGH;
670 * Returns true if this provider meets the given criteria,
673 public boolean meetsCriteria(Criteria criteria) {
674 return (criteria.getPowerRequirement() != Criteria.POWER_LOW);
678 * Returns the horizontal accuracy of this provider
680 * @return the accuracy of location from this provider, as one
681 * of the constants Criteria.ACCURACY_*.
683 public int getAccuracy() {
684 return Criteria.ACCURACY_FINE;
688 * Enables this provider. When enabled, calls to getStatus()
689 * must be handled. Hardware may be started up
690 * when the provider is enabled.
692 public void enable() {
693 synchronized (mHandler) {
694 sendMessage(ENABLE, 1, null);
698 private void handleEnable() {
699 if (DEBUG) Log.d(TAG, "handleEnable");
700 if (mEnabled) return;
701 mEnabled = native_init();
704 mSupportsXtra = native_supports_xtra();
705 if (mSuplServerHost != null) {
706 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
708 if (mC2KServerHost != null) {
709 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
712 Log.w(TAG, "Failed to enable location provider");
717 * Disables this provider. When disabled, calls to getStatus()
718 * need not be handled. Hardware may be shut
719 * down while the provider is disabled.
721 public void disable() {
722 synchronized (mHandler) {
723 sendMessage(ENABLE, 0, null);
727 private void handleDisable() {
728 if (DEBUG) Log.d(TAG, "handleDisable");
729 if (!mEnabled) return;
734 // do this before releasing wakelock
738 public boolean isEnabled() {
742 public int getStatus(Bundle extras) {
743 if (extras != null) {
744 extras.putInt("satellites", mSvCount);
749 private void updateStatus(int status, int svCount) {
750 if (status != mStatus || svCount != mSvCount) {
753 mLocationExtras.putInt("satellites", svCount);
754 mStatusUpdateTime = SystemClock.elapsedRealtime();
758 public long getStatusUpdateTime() {
759 return mStatusUpdateTime;
762 public void enableLocationTracking(boolean enable) {
763 // FIXME - should set a flag here to avoid race conditions with single shot request
764 synchronized (mHandler) {
765 sendMessage(ENABLE_TRACKING, (enable ? 1 : 0), null);
769 private void handleEnableLocationTracking(boolean enable) {
773 startNavigating(false);
775 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
776 mAlarmManager.cancel(mWakeupIntent);
777 mAlarmManager.cancel(mTimeoutIntent);
783 public boolean requestSingleShotFix() {
785 // cannot do single shot if already navigating
788 synchronized (mHandler) {
789 mHandler.removeMessages(REQUEST_SINGLE_SHOT);
790 Message m = Message.obtain(mHandler, REQUEST_SINGLE_SHOT);
791 mHandler.sendMessage(m);
796 private void handleRequestSingleShot() {
799 startNavigating(true);
802 public void setMinTime(long minTime, WorkSource ws) {
803 if (DEBUG) Log.d(TAG, "setMinTime " + minTime);
806 mFixInterval = (int)minTime;
808 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
809 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
810 mFixInterval, 0, 0)) {
811 Log.e(TAG, "set_position_mode failed in setMinTime()");
817 public String getInternalState() {
818 return native_get_internal_state();
821 private final class Listener implements IBinder.DeathRecipient {
822 final IGpsStatusListener mListener;
826 Listener(IGpsStatusListener listener) {
827 mListener = listener;
830 public void binderDied() {
831 if (DEBUG) Log.d(TAG, "GPS status listener died");
833 synchronized(mListeners) {
834 mListeners.remove(this);
836 if (mListener != null) {
837 mListener.asBinder().unlinkToDeath(this, 0);
842 public void addListener(int uid) {
843 synchronized (mWakeLock) {
844 mPendingListenerMessages++;
846 Message m = Message.obtain(mHandler, ADD_LISTENER);
848 mHandler.sendMessage(m);
852 private void handleAddListener(int uid) {
853 synchronized(mListeners) {
854 if (mClientUids.indexOfKey(uid) >= 0) {
855 // Shouldn't be here -- already have this uid.
856 Log.w(TAG, "Duplicate add listener for uid " + uid);
859 mClientUids.put(uid, 0);
862 mBatteryStats.noteStartGps(uid);
863 } catch (RemoteException e) {
864 Log.w(TAG, "RemoteException in addListener");
870 public void removeListener(int uid) {
871 synchronized (mWakeLock) {
872 mPendingListenerMessages++;
874 Message m = Message.obtain(mHandler, REMOVE_LISTENER);
876 mHandler.sendMessage(m);
880 private void handleRemoveListener(int uid) {
881 synchronized(mListeners) {
882 if (mClientUids.indexOfKey(uid) < 0) {
883 // Shouldn't be here -- don't have this uid.
884 Log.w(TAG, "Unneeded remove listener for uid " + uid);
887 mClientUids.delete(uid);
890 mBatteryStats.noteStopGps(uid);
891 } catch (RemoteException e) {
892 Log.w(TAG, "RemoteException in removeListener");
898 public boolean sendExtraCommand(String command, Bundle extras) {
900 long identity = Binder.clearCallingIdentity();
901 boolean result = false;
903 if ("delete_aiding_data".equals(command)) {
904 result = deleteAidingData(extras);
905 } else if ("force_time_injection".equals(command)) {
906 sendMessage(INJECT_NTP_TIME, 0, null);
908 } else if ("force_xtra_injection".equals(command)) {
910 xtraDownloadRequest();
914 Log.w(TAG, "sendExtraCommand: unknown command " + command);
917 Binder.restoreCallingIdentity(identity);
921 private boolean deleteAidingData(Bundle extras) {
924 if (extras == null) {
925 flags = GPS_DELETE_ALL;
928 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
929 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
930 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
931 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
932 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
933 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
934 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
935 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
936 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
937 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
938 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
939 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
940 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
944 native_delete_aiding_data(flags);
951 private void startNavigating(boolean singleShot) {
953 if (DEBUG) Log.d(TAG, "startNavigating");
955 mSingleShot = singleShot;
956 mPositionMode = GPS_POSITION_MODE_STANDALONE;
958 if (Settings.Secure.getInt(mContext.getContentResolver(),
959 Settings.Secure.ASSISTED_GPS_ENABLED, 1) != 0) {
960 if (singleShot && hasCapability(GPS_CAPABILITY_MSA)) {
961 mPositionMode = GPS_POSITION_MODE_MS_ASSISTED;
962 } else if (hasCapability(GPS_CAPABILITY_MSB)) {
963 mPositionMode = GPS_POSITION_MODE_MS_BASED;
967 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
968 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
971 Log.e(TAG, "set_position_mode failed in startNavigating()");
974 if (!native_start()) {
976 Log.e(TAG, "native_start failed in startNavigating()");
980 // reset SV count to zero
981 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
982 mFixRequestTime = System.currentTimeMillis();
983 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
984 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
985 // and our fix interval is not short
986 if (mFixInterval >= NO_FIX_TIMEOUT) {
987 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
988 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
994 private void stopNavigating() {
995 if (DEBUG) Log.d(TAG, "stopNavigating");
1002 mLocationFlags = LOCATION_INVALID;
1004 // reset SV count to zero
1005 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1009 private void hibernate() {
1010 // stop GPS until our next fix interval arrives
1012 mAlarmManager.cancel(mTimeoutIntent);
1013 mAlarmManager.cancel(mWakeupIntent);
1014 long now = SystemClock.elapsedRealtime();
1015 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1016 SystemClock.elapsedRealtime() + mFixInterval, mWakeupIntent);
1019 private boolean hasCapability(int capability) {
1020 return ((mEngineCapabilities & capability) != 0);
1024 * called from native code to update our position.
1026 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1027 float speed, float bearing, float accuracy, long timestamp) {
1028 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1029 " timestamp: " + timestamp);
1031 synchronized (mLocation) {
1032 mLocationFlags = flags;
1033 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1034 mLocation.setLatitude(latitude);
1035 mLocation.setLongitude(longitude);
1036 mLocation.setTime(timestamp);
1038 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1039 mLocation.setAltitude(altitude);
1041 mLocation.removeAltitude();
1043 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1044 mLocation.setSpeed(speed);
1046 mLocation.removeSpeed();
1048 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1049 mLocation.setBearing(bearing);
1051 mLocation.removeBearing();
1053 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1054 mLocation.setAccuracy(accuracy);
1056 mLocation.removeAccuracy();
1060 mLocationManager.reportLocation(mLocation, false);
1061 } catch (RemoteException e) {
1062 Log.e(TAG, "RemoteException calling reportLocation");
1066 mLastFixTime = System.currentTimeMillis();
1067 // report time to first fix
1068 if (mTTFF == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1069 mTTFF = (int)(mLastFixTime - mFixRequestTime);
1070 if (DEBUG) Log.d(TAG, "TTFF: " + mTTFF);
1072 // notify status listeners
1073 synchronized(mListeners) {
1074 int size = mListeners.size();
1075 for (int i = 0; i < size; i++) {
1076 Listener listener = mListeners.get(i);
1078 listener.mListener.onFirstFix(mTTFF);
1079 } catch (RemoteException e) {
1080 Log.w(TAG, "RemoteException in stopNavigating");
1081 mListeners.remove(listener);
1082 // adjust for size of list changing
1092 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1093 // we want to time out if we do not receive a fix
1094 // within the time out and we are requesting infrequent fixes
1095 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1096 mAlarmManager.cancel(mTimeoutIntent);
1099 // send an intent to notify that the GPS is receiving fixes.
1100 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1101 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1102 mContext.sendBroadcast(intent);
1103 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1106 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted && mFixInterval > 1000) {
1107 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1113 * called from native code to update our status
1115 private void reportStatus(int status) {
1116 if (VERBOSE) Log.v(TAG, "reportStatus status: " + status);
1118 synchronized(mListeners) {
1119 boolean wasNavigating = mNavigating;
1122 case GPS_STATUS_SESSION_BEGIN:
1126 case GPS_STATUS_SESSION_END:
1127 mNavigating = false;
1129 case GPS_STATUS_ENGINE_ON:
1132 case GPS_STATUS_ENGINE_OFF:
1134 mNavigating = false;
1138 if (wasNavigating != mNavigating) {
1139 int size = mListeners.size();
1140 for (int i = 0; i < size; i++) {
1141 Listener listener = mListeners.get(i);
1144 listener.mListener.onGpsStarted();
1146 listener.mListener.onGpsStopped();
1148 } catch (RemoteException e) {
1149 Log.w(TAG, "RemoteException in reportStatus");
1150 mListeners.remove(listener);
1151 // adjust for size of list changing
1157 // update battery stats
1158 for (int i=mClientUids.size() - 1; i >= 0; i--) {
1159 int uid = mClientUids.keyAt(i);
1161 mBatteryStats.noteStartGps(uid);
1163 mBatteryStats.noteStopGps(uid);
1166 } catch (RemoteException e) {
1167 Log.w(TAG, "RemoteException in reportStatus");
1170 // send an intent to notify that the GPS has been enabled or disabled.
1171 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1172 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1173 mContext.sendBroadcast(intent);
1179 * called from native code to update SV info
1181 private void reportSvStatus() {
1183 int svCount = native_read_sv_status(mSvs, mSnrs, mSvElevations, mSvAzimuths, mSvMasks);
1185 synchronized(mListeners) {
1186 int size = mListeners.size();
1187 for (int i = 0; i < size; i++) {
1188 Listener listener = mListeners.get(i);
1190 listener.mListener.onSvStatusChanged(svCount, mSvs, mSnrs,
1191 mSvElevations, mSvAzimuths, mSvMasks[EPHEMERIS_MASK],
1192 mSvMasks[ALMANAC_MASK], mSvMasks[USED_FOR_FIX_MASK]);
1193 } catch (RemoteException e) {
1194 Log.w(TAG, "RemoteException in reportSvInfo");
1195 mListeners.remove(listener);
1196 // adjust for size of list changing
1203 Log.v(TAG, "SV count: " + svCount +
1204 " ephemerisMask: " + Integer.toHexString(mSvMasks[EPHEMERIS_MASK]) +
1205 " almanacMask: " + Integer.toHexString(mSvMasks[ALMANAC_MASK]));
1206 for (int i = 0; i < svCount; i++) {
1207 Log.v(TAG, "sv: " + mSvs[i] +
1208 " snr: " + (float)mSnrs[i]/10 +
1209 " elev: " + mSvElevations[i] +
1210 " azimuth: " + mSvAzimuths[i] +
1211 ((mSvMasks[EPHEMERIS_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " E") +
1212 ((mSvMasks[ALMANAC_MASK] & (1 << (mSvs[i] - 1))) == 0 ? " " : " A") +
1213 ((mSvMasks[USED_FOR_FIX_MASK] & (1 << (mSvs[i] - 1))) == 0 ? "" : "U"));
1217 // return number of sets used in fix instead of total
1218 updateStatus(mStatus, Integer.bitCount(mSvMasks[USED_FOR_FIX_MASK]));
1220 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1221 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1222 // send an intent to notify that the GPS is no longer receiving fixes.
1223 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1224 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1225 mContext.sendBroadcast(intent);
1226 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1231 * called from native code to update AGPS status
1233 private void reportAGpsStatus(int type, int status) {
1235 case GPS_REQUEST_AGPS_DATA_CONN:
1236 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1237 // Set mAGpsDataConnectionState before calling startUsingNetworkFeature
1238 // to avoid a race condition with handleUpdateNetworkState()
1239 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
1240 int result = mConnMgr.startUsingNetworkFeature(
1241 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
1242 if (result == Phone.APN_ALREADY_ACTIVE) {
1243 if (DEBUG) Log.d(TAG, "Phone.APN_ALREADY_ACTIVE");
1244 if (mAGpsApn != null) {
1245 native_agps_data_conn_open(mAGpsApn);
1246 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
1248 Log.e(TAG, "mAGpsApn not set when receiving Phone.APN_ALREADY_ACTIVE");
1249 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1250 native_agps_data_conn_failed();
1252 } else if (result == Phone.APN_REQUEST_STARTED) {
1253 // Nothing to do here
1255 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1256 native_agps_data_conn_failed();
1259 case GPS_RELEASE_AGPS_DATA_CONN:
1260 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1261 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
1262 mConnMgr.stopUsingNetworkFeature(
1263 ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_SUPL);
1264 native_agps_data_conn_closed();
1265 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
1268 case GPS_AGPS_DATA_CONNECTED:
1269 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1271 case GPS_AGPS_DATA_CONN_DONE:
1272 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1274 case GPS_AGPS_DATA_CONN_FAILED:
1275 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1281 * called from native code to report NMEA data received
1283 private void reportNmea(long timestamp) {
1284 synchronized(mListeners) {
1285 int size = mListeners.size();
1287 // don't bother creating the String if we have no listeners
1288 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1289 String nmea = new String(mNmeaBuffer, 0, length);
1291 for (int i = 0; i < size; i++) {
1292 Listener listener = mListeners.get(i);
1294 listener.mListener.onNmeaReceived(timestamp, nmea);
1295 } catch (RemoteException e) {
1296 Log.w(TAG, "RemoteException in reportNmea");
1297 mListeners.remove(listener);
1298 // adjust for size of list changing
1307 * called from native code to inform us what the GPS engine capabilities are
1309 private void setEngineCapabilities(int capabilities) {
1310 mEngineCapabilities = capabilities;
1314 * called from native code to request XTRA data
1316 private void xtraDownloadRequest() {
1317 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1318 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1321 //=============================================================
1322 // NI Client support
1323 //=============================================================
1324 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1325 // Sends a response for an NI reqeust to HAL.
1326 public boolean sendNiResponse(int notificationId, int userResponse)
1328 // TODO Add Permission check
1330 StringBuilder extrasBuf = new StringBuilder();
1332 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1333 ", response: " + userResponse);
1334 native_send_ni_response(notificationId, userResponse);
1339 public INetInitiatedListener getNetInitiatedListener() {
1340 return mNetInitiatedListener;
1343 // Called by JNI function to report an NI request.
1344 public void reportNiNotification(
1349 int defaultResponse,
1352 int requestorIdEncoding,
1354 String extras // Encoded extra data
1357 Log.i(TAG, "reportNiNotification: entered");
1358 Log.i(TAG, "notificationId: " + notificationId +
1359 ", niType: " + niType +
1360 ", notifyFlags: " + notifyFlags +
1361 ", timeout: " + timeout +
1362 ", defaultResponse: " + defaultResponse);
1364 Log.i(TAG, "requestorId: " + requestorId +
1366 ", requestorIdEncoding: " + requestorIdEncoding +
1367 ", textEncoding: " + textEncoding);
1369 GpsNiNotification notification = new GpsNiNotification();
1371 notification.notificationId = notificationId;
1372 notification.niType = niType;
1373 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1374 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1375 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1376 notification.timeout = timeout;
1377 notification.defaultResponse = defaultResponse;
1378 notification.requestorId = requestorId;
1379 notification.text = text;
1380 notification.requestorIdEncoding = requestorIdEncoding;
1381 notification.textEncoding = textEncoding;
1383 // Process extras, assuming the format is
1384 // one of more lines of "key = value"
1385 Bundle bundle = new Bundle();
1387 if (extras == null) extras = "";
1388 Properties extraProp = new Properties();
1391 extraProp.load(new StringBufferInputStream(extras));
1393 catch (IOException e)
1395 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1398 for (Entry<Object, Object> ent : extraProp.entrySet())
1400 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1403 notification.extras = bundle;
1405 mNIHandler.handleNiNotification(notification);
1409 * Called from native code to request set id info.
1410 * We should be careful about receiving null string from the TelephonyManager,
1411 * because sending null String to JNI function would cause a crash.
1414 private void requestSetID(int flags) {
1415 TelephonyManager phone = (TelephonyManager)
1416 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1417 int type = AGPS_SETID_TYPE_NONE;
1420 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1421 String data_temp = phone.getSubscriberId();
1422 if (data_temp == null) {
1423 // This means the framework does not have the SIM card ready.
1425 // This means the framework has the SIM card.
1427 type = AGPS_SETID_TYPE_IMSI;
1430 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1431 String data_temp = phone.getLine1Number();
1432 if (data_temp == null) {
1433 // This means the framework does not have the SIM card ready.
1435 // This means the framework has the SIM card.
1437 type = AGPS_SETID_TYPE_MSISDN;
1440 native_agps_set_id(type, data);
1444 * Called from native code to request reference location info
1447 private void requestRefLocation(int flags) {
1448 TelephonyManager phone = (TelephonyManager)
1449 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1450 if (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM) {
1451 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
1452 if ((gsm_cell != null) && (phone.getPhoneType() == TelephonyManager.PHONE_TYPE_GSM)
1453 && (phone.getNetworkOperator().length() > 3)) {
1455 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
1456 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
1457 if (phone.getNetworkType() == TelephonyManager.NETWORK_TYPE_UMTS)
1458 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
1460 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
1461 native_agps_set_ref_location_cellid(type, mcc, mnc,
1462 gsm_cell.getLac(), gsm_cell.getCid());
1465 Log.e(TAG,"Error getting cell location info.");
1468 Log.e(TAG,"CDMA not supported.");
1471 private void sendMessage(int message, int arg, Object obj) {
1472 // hold a wake lock while messages are pending
1473 synchronized (mWakeLock) {
1474 mPendingMessageBits |= (1 << message);
1475 mWakeLock.acquire();
1476 mHandler.removeMessages(message);
1477 Message m = Message.obtain(mHandler, message);
1480 mHandler.sendMessage(m);
1484 private final class ProviderHandler extends Handler {
1486 public void handleMessage(Message msg)
1488 int message = msg.what;
1491 if (msg.arg1 == 1) {
1497 case ENABLE_TRACKING:
1498 handleEnableLocationTracking(msg.arg1 == 1);
1500 case REQUEST_SINGLE_SHOT:
1501 handleRequestSingleShot();
1503 case UPDATE_NETWORK_STATE:
1504 handleUpdateNetworkState(msg.arg1, (NetworkInfo)msg.obj);
1506 case INJECT_NTP_TIME:
1507 handleInjectNtpTime();
1509 case DOWNLOAD_XTRA_DATA:
1510 if (mSupportsXtra) {
1511 handleDownloadXtraData();
1514 case UPDATE_LOCATION:
1515 handleUpdateLocation((Location)msg.obj);
1518 handleAddListener(msg.arg1);
1520 case REMOVE_LISTENER:
1521 handleRemoveListener(msg.arg1);
1524 // release wake lock if no messages are pending
1525 synchronized (mWakeLock) {
1526 mPendingMessageBits &= ~(1 << message);
1527 if (message == ADD_LISTENER || message == REMOVE_LISTENER) {
1528 mPendingListenerMessages--;
1530 if (mPendingMessageBits == 0 && mPendingListenerMessages == 0) {
1531 mWakeLock.release();
1537 private final class GpsLocationProviderThread extends Thread {
1539 public GpsLocationProviderThread() {
1540 super("GpsLocationProvider");
1544 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
1547 mHandler = new ProviderHandler();
1548 // signal when we are initialized and ready to go
1549 mInitializedLatch.countDown();
1554 // for GPS SV statistics
1555 private static final int MAX_SVS = 32;
1556 private static final int EPHEMERIS_MASK = 0;
1557 private static final int ALMANAC_MASK = 1;
1558 private static final int USED_FOR_FIX_MASK = 2;
1560 // preallocated arrays, to avoid memory allocation in reportStatus()
1561 private int mSvs[] = new int[MAX_SVS];
1562 private float mSnrs[] = new float[MAX_SVS];
1563 private float mSvElevations[] = new float[MAX_SVS];
1564 private float mSvAzimuths[] = new float[MAX_SVS];
1565 private int mSvMasks[] = new int[3];
1566 private int mSvCount;
1567 // preallocated to avoid memory allocation in reportNmea()
1568 private byte[] mNmeaBuffer = new byte[120];
1570 static { class_init_native(); }
1571 private static native void class_init_native();
1572 private static native boolean native_is_supported();
1574 private native boolean native_init();
1575 private native void native_cleanup();
1576 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
1577 int preferred_accuracy, int preferred_time);
1578 private native boolean native_start();
1579 private native boolean native_stop();
1580 private native void native_delete_aiding_data(int flags);
1581 // returns number of SVs
1582 // mask[0] is ephemeris mask and mask[1] is almanac mask
1583 private native int native_read_sv_status(int[] svs, float[] snrs,
1584 float[] elevations, float[] azimuths, int[] masks);
1585 private native int native_read_nmea(byte[] buffer, int bufferSize);
1586 private native void native_inject_location(double latitude, double longitude, float accuracy);
1589 private native void native_inject_time(long time, long timeReference, int uncertainty);
1590 private native boolean native_supports_xtra();
1591 private native void native_inject_xtra_data(byte[] data, int length);
1594 private native String native_get_internal_state();
1597 private native void native_agps_data_conn_open(String apn);
1598 private native void native_agps_data_conn_closed();
1599 private native void native_agps_data_conn_failed();
1600 private native void native_agps_ni_message(byte [] msg, int length);
1601 private native void native_set_agps_server(int type, String hostname, int port);
1603 // Network-initiated (NI) Support
1604 private native void native_send_ni_response(int notificationId, int userResponse);
1607 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
1609 private native void native_agps_set_id(int type, String setid);
1611 private native void native_update_network_state(boolean connected, int type,
1612 boolean roaming, String extraInfo);