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 com.android.internal.app.IAppOpsService;
20 import com.android.internal.app.IBatteryStats;
21 import com.android.internal.location.GpsNetInitiatedHandler;
22 import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
23 import com.android.internal.location.ProviderProperties;
24 import com.android.internal.location.ProviderRequest;
26 import android.app.AlarmManager;
27 import android.app.AppOpsManager;
28 import android.app.PendingIntent;
29 import android.content.BroadcastReceiver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.IntentFilter;
33 import android.database.Cursor;
34 import android.hardware.location.GeofenceHardware;
35 import android.hardware.location.GeofenceHardwareImpl;
36 import android.location.Criteria;
37 import android.location.FusedBatchOptions;
38 import android.location.GnssStatus;
39 import android.location.IGnssStatusListener;
40 import android.location.IGnssStatusProvider;
41 import android.location.GnssMeasurementsEvent;
42 import android.location.GnssNavigationMessage;
43 import android.location.IGpsGeofenceHardware;
44 import android.location.ILocationManager;
45 import android.location.INetInitiatedListener;
46 import android.location.Location;
47 import android.location.LocationListener;
48 import android.location.LocationManager;
49 import android.location.LocationProvider;
50 import android.location.LocationRequest;
51 import android.net.ConnectivityManager;
52 import android.net.Network;
53 import android.net.NetworkCapabilities;
54 import android.net.NetworkInfo;
55 import android.net.NetworkRequest;
56 import android.net.Uri;
57 import android.os.AsyncTask;
58 import android.os.BatteryStats;
59 import android.os.Binder;
60 import android.os.Bundle;
61 import android.os.Handler;
62 import android.os.Looper;
63 import android.os.Message;
64 import android.os.PowerManager;
65 import android.os.RemoteException;
66 import android.os.ServiceManager;
67 import android.os.SystemClock;
68 import android.os.SystemProperties;
69 import android.os.UserHandle;
70 import android.os.WorkSource;
71 import android.provider.Settings;
72 import android.provider.Telephony.Carriers;
73 import android.provider.Telephony.Sms.Intents;
74 import android.telephony.SmsMessage;
75 import android.telephony.SubscriptionManager;
76 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
77 import android.telephony.TelephonyManager;
78 import android.telephony.gsm.GsmCellLocation;
79 import android.text.TextUtils;
80 import android.util.Log;
81 import android.util.NtpTrustedTime;
83 import java.io.ByteArrayOutputStream;
85 import java.io.FileDescriptor;
86 import java.io.FileInputStream;
87 import java.io.IOException;
88 import java.io.PrintWriter;
89 import java.io.StringReader;
90 import java.net.InetAddress;
91 import java.net.UnknownHostException;
92 import java.util.Arrays;
93 import java.util.Date;
94 import java.util.Map.Entry;
95 import java.util.Properties;
97 import libcore.io.IoUtils;
100 * A GPS implementation of LocationProvider used by LocationManager.
104 public class GnssLocationProvider implements LocationProviderInterface {
106 private static final String TAG = "GnssLocationProvider";
108 private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
109 private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
111 private static final ProviderProperties PROPERTIES = new ProviderProperties(
112 true, true, false, false, true, true, true,
113 Criteria.POWER_HIGH, Criteria.ACCURACY_FINE);
115 // these need to match GpsPositionMode enum in gps.h
116 private static final int GPS_POSITION_MODE_STANDALONE = 0;
117 private static final int GPS_POSITION_MODE_MS_BASED = 1;
118 private static final int GPS_POSITION_MODE_MS_ASSISTED = 2;
120 // these need to match GpsPositionRecurrence enum in gps.h
121 private static final int GPS_POSITION_RECURRENCE_PERIODIC = 0;
122 private static final int GPS_POSITION_RECURRENCE_SINGLE = 1;
124 // these need to match GpsStatusValue defines in gps.h
125 private static final int GPS_STATUS_NONE = 0;
126 private static final int GPS_STATUS_SESSION_BEGIN = 1;
127 private static final int GPS_STATUS_SESSION_END = 2;
128 private static final int GPS_STATUS_ENGINE_ON = 3;
129 private static final int GPS_STATUS_ENGINE_OFF = 4;
131 // these need to match GpsApgsStatusValue defines in gps.h
132 /** AGPS status event values. */
133 private static final int GPS_REQUEST_AGPS_DATA_CONN = 1;
134 private static final int GPS_RELEASE_AGPS_DATA_CONN = 2;
135 private static final int GPS_AGPS_DATA_CONNECTED = 3;
136 private static final int GPS_AGPS_DATA_CONN_DONE = 4;
137 private static final int GPS_AGPS_DATA_CONN_FAILED = 5;
139 // these need to match GpsLocationFlags enum in gps.h
140 private static final int LOCATION_INVALID = 0;
141 private static final int LOCATION_HAS_LAT_LONG = 1;
142 private static final int LOCATION_HAS_ALTITUDE = 2;
143 private static final int LOCATION_HAS_SPEED = 4;
144 private static final int LOCATION_HAS_BEARING = 8;
145 private static final int LOCATION_HAS_ACCURACY = 16;
147 // IMPORTANT - the GPS_DELETE_* symbols here must match constants in gps.h
148 private static final int GPS_DELETE_EPHEMERIS = 0x0001;
149 private static final int GPS_DELETE_ALMANAC = 0x0002;
150 private static final int GPS_DELETE_POSITION = 0x0004;
151 private static final int GPS_DELETE_TIME = 0x0008;
152 private static final int GPS_DELETE_IONO = 0x0010;
153 private static final int GPS_DELETE_UTC = 0x0020;
154 private static final int GPS_DELETE_HEALTH = 0x0040;
155 private static final int GPS_DELETE_SVDIR = 0x0080;
156 private static final int GPS_DELETE_SVSTEER = 0x0100;
157 private static final int GPS_DELETE_SADATA = 0x0200;
158 private static final int GPS_DELETE_RTI = 0x0400;
159 private static final int GPS_DELETE_CELLDB_INFO = 0x8000;
160 private static final int GPS_DELETE_ALL = 0xFFFF;
162 // The GPS_CAPABILITY_* flags must match the values in gps.h
163 private static final int GPS_CAPABILITY_SCHEDULING = 0x0000001;
164 private static final int GPS_CAPABILITY_MSB = 0x0000002;
165 private static final int GPS_CAPABILITY_MSA = 0x0000004;
166 private static final int GPS_CAPABILITY_SINGLE_SHOT = 0x0000008;
167 private static final int GPS_CAPABILITY_ON_DEMAND_TIME = 0x0000010;
168 private static final int GPS_CAPABILITY_GEOFENCING = 0x0000020;
169 private static final int GPS_CAPABILITY_MEASUREMENTS = 0x0000040;
170 private static final int GPS_CAPABILITY_NAV_MESSAGES = 0x0000080;
172 // The AGPS SUPL mode
173 private static final int AGPS_SUPL_MODE_MSA = 0x02;
174 private static final int AGPS_SUPL_MODE_MSB = 0x01;
176 // these need to match AGpsType enum in gps.h
177 private static final int AGPS_TYPE_SUPL = 1;
178 private static final int AGPS_TYPE_C2K = 2;
180 // these must match the definitions in gps.h
181 private static final int APN_INVALID = 0;
182 private static final int APN_IPV4 = 1;
183 private static final int APN_IPV6 = 2;
184 private static final int APN_IPV4V6 = 3;
186 // for mAGpsDataConnectionState
187 private static final int AGPS_DATA_CONNECTION_CLOSED = 0;
188 private static final int AGPS_DATA_CONNECTION_OPENING = 1;
189 private static final int AGPS_DATA_CONNECTION_OPEN = 2;
192 private static final int CHECK_LOCATION = 1;
193 private static final int ENABLE = 2;
194 private static final int SET_REQUEST = 3;
195 private static final int UPDATE_NETWORK_STATE = 4;
196 private static final int INJECT_NTP_TIME = 5;
197 private static final int DOWNLOAD_XTRA_DATA = 6;
198 private static final int UPDATE_LOCATION = 7;
199 private static final int ADD_LISTENER = 8;
200 private static final int REMOVE_LISTENER = 9;
201 private static final int INJECT_NTP_TIME_FINISHED = 10;
202 private static final int DOWNLOAD_XTRA_DATA_FINISHED = 11;
203 private static final int SUBSCRIPTION_OR_SIM_CHANGED = 12;
204 private static final int INITIALIZE_HANDLER = 13;
205 private static final int REQUEST_SUPL_CONNECTION = 14;
206 private static final int RELEASE_SUPL_CONNECTION = 15;
209 private static final int AGPS_RIL_REQUEST_SETID_IMSI = 1;
210 private static final int AGPS_RIL_REQUEST_SETID_MSISDN = 2;
212 // Request ref location
213 private static final int AGPS_RIL_REQUEST_REFLOC_CELLID = 1;
214 private static final int AGPS_RIL_REQUEST_REFLOC_MAC = 2;
216 // ref. location info
217 private static final int AGPS_REF_LOCATION_TYPE_GSM_CELLID = 1;
218 private static final int AGPS_REF_LOCATION_TYPE_UMTS_CELLID = 2;
219 private static final int AGPS_REG_LOCATION_TYPE_MAC = 3;
222 private static final int AGPS_SETID_TYPE_NONE = 0;
223 private static final int AGPS_SETID_TYPE_IMSI = 1;
224 private static final int AGPS_SETID_TYPE_MSISDN = 2;
226 private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
227 private static final String PROPERTIES_FILE_SUFFIX = ".conf";
228 private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
230 private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
231 private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
233 // GPS Geofence errors. Should match gps.h constants.
234 private static final int GPS_GEOFENCE_OPERATION_SUCCESS = 0;
235 private static final int GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES = 100;
236 private static final int GPS_GEOFENCE_ERROR_ID_EXISTS = -101;
237 private static final int GPS_GEOFENCE_ERROR_ID_UNKNOWN = -102;
238 private static final int GPS_GEOFENCE_ERROR_INVALID_TRANSITION = -103;
239 private static final int GPS_GEOFENCE_ERROR_GENERIC = -149;
242 // Valid TCP/UDP port range is (0, 65535].
243 private static final int TCP_MIN_PORT = 0;
244 private static final int TCP_MAX_PORT = 0xffff;
246 // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
247 private static final int BATTERY_SAVER_MODE_NO_CHANGE = 0;
248 // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
249 // is enabled and the screen is off.
250 private static final int BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
251 // Secure setting for GPS behavior when battery saver mode is on.
252 private static final String BATTERY_SAVER_GPS_MODE = "batterySaverGpsMode";
254 /** simpler wrapper for ProviderRequest + Worksource */
255 private static class GpsRequest {
256 public ProviderRequest request;
257 public WorkSource source;
258 public GpsRequest(ProviderRequest request, WorkSource source) {
259 this.request = request;
260 this.source = source;
264 private Object mLock = new Object();
266 private int mLocationFlags = LOCATION_INVALID;
269 private int mStatus = LocationProvider.TEMPORARILY_UNAVAILABLE;
271 // time for last status update
272 private long mStatusUpdateTime = SystemClock.elapsedRealtime();
274 // turn off GPS fix icon if we haven't received a fix in 10 seconds
275 private static final long RECENT_FIX_TIMEOUT = 10 * 1000;
277 // stop trying if we do not receive a fix within 60 seconds
278 private static final int NO_FIX_TIMEOUT = 60 * 1000;
280 // if the fix interval is below this we leave GPS on,
281 // if above then we cycle the GPS driver.
282 // Typical hot TTTF is ~5 seconds, so 10 seconds seems sane.
283 private static final int GPS_POLLING_THRESHOLD_INTERVAL = 10 * 1000;
285 // how often to request NTP time, in milliseconds
286 // current setting 24 hours
287 private static final long NTP_INTERVAL = 24*60*60*1000;
288 // how long to wait if we have a network error in NTP or XTRA downloading
289 // the initial value of the exponential backoff
290 // current setting - 5 minutes
291 private static final long RETRY_INTERVAL = 5*60*1000;
292 // how long to wait if we have a network error in NTP or XTRA downloading
293 // the max value of the exponential backoff
294 // current setting - 4 hours
295 private static final long MAX_RETRY_INTERVAL = 4*60*60*1000;
297 private BackOff mNtpBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
298 private BackOff mXtraBackOff = new BackOff(RETRY_INTERVAL, MAX_RETRY_INTERVAL);
300 // true if we are enabled, protected by this
301 private boolean mEnabled;
303 // states for injecting ntp and downloading xtra data
304 private static final int STATE_PENDING_NETWORK = 0;
305 private static final int STATE_DOWNLOADING = 1;
306 private static final int STATE_IDLE = 2;
308 // flags to trigger NTP or XTRA data download when network becomes available
309 // initialized to true so we do NTP and XTRA when the network comes up after booting
310 private int mInjectNtpTimePending = STATE_PENDING_NETWORK;
311 private int mDownloadXtraDataPending = STATE_PENDING_NETWORK;
313 // set to true if the GPS engine requested on-demand NTP time requests
314 private boolean mOnDemandTimeInjection;
316 // true if GPS is navigating
317 private boolean mNavigating;
319 // true if GPS engine is on
320 private boolean mEngineOn;
322 // requested frequency of fixes, in milliseconds
323 private int mFixInterval = 1000;
325 // true if we started navigation
326 private boolean mStarted;
328 // true if single shot request is in progress
329 private boolean mSingleShot;
331 // capabilities of the GPS engine
332 private int mEngineCapabilities;
334 // true if XTRA is supported
335 private boolean mSupportsXtra;
337 // for calculating time to first fix
338 private long mFixRequestTime = 0;
339 // time to first fix for most recent session
340 private int mTimeToFirstFix = 0;
341 // time we received our last fix
342 private long mLastFixTime;
344 private int mPositionMode;
346 // Current request from underlying location clients.
347 private ProviderRequest mProviderRequest = null;
348 // Current list of underlying location clients.
349 private WorkSource mWorkSource = null;
350 // True if gps should be disabled (used to support battery saver mode in settings).
351 private boolean mDisableGps = false;
354 * Properties loaded from PROPERTIES_FILE.
355 * It must be accessed only inside {@link #mHandler}.
357 private Properties mProperties;
359 private String mSuplServerHost;
360 private int mSuplServerPort = TCP_MIN_PORT;
361 private String mC2KServerHost;
362 private int mC2KServerPort;
363 private boolean mSuplEsEnabled = false;
365 private final Context mContext;
366 private final NtpTrustedTime mNtpTime;
367 private final ILocationManager mILocationManager;
368 private Location mLocation = new Location(LocationManager.GPS_PROVIDER);
369 private Bundle mLocationExtras = new Bundle();
370 private final GnssStatusListenerHelper mListenerHelper;
371 private final GnssMeasurementsProvider mGnssMeasurementsProvider;
372 private final GnssNavigationMessageProvider mGnssNavigationMessageProvider;
374 // Handler for processing events
375 private Handler mHandler;
377 /** It must be accessed only inside {@link #mHandler}. */
378 private int mAGpsDataConnectionState;
379 /** It must be accessed only inside {@link #mHandler}. */
380 private InetAddress mAGpsDataConnectionIpAddr;
382 private final ConnectivityManager mConnMgr;
383 private final GpsNetInitiatedHandler mNIHandler;
386 private final static String WAKELOCK_KEY = "GnssLocationProvider";
387 private final PowerManager.WakeLock mWakeLock;
390 private final static String ALARM_WAKEUP = "com.android.internal.location.ALARM_WAKEUP";
391 private final static String ALARM_TIMEOUT = "com.android.internal.location.ALARM_TIMEOUT";
394 private final static String SIM_STATE_CHANGED = "android.intent.action.SIM_STATE_CHANGED";
396 // Persist property for LPP_PROFILE
397 private final static String LPP_PROFILE = "persist.sys.gps.lpp";
400 private static final String[] VzwMccMncList = {"311480", "310004", "20404"};
401 // corresponding GID1 value, empty string means ignore gid1 match.
402 private static final String[] VzwGid1List = {"", "", "BAE0000000000000"};
405 private final PowerManager mPowerManager;
406 private final AlarmManager mAlarmManager;
407 private final PendingIntent mWakeupIntent;
408 private final PendingIntent mTimeoutIntent;
410 private final IAppOpsService mAppOpsService;
411 private final IBatteryStats mBatteryStats;
413 // only modified on handler thread
414 private WorkSource mClientSource = new WorkSource();
416 private GeofenceHardwareImpl mGeofenceHardwareImpl;
418 private int mYearOfHardware = 0;
420 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
422 public void registerGnssStatusCallback(IGnssStatusListener callback) {
423 mListenerHelper.addListener(callback);
427 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
428 mListenerHelper.removeListener(callback);
432 public IGnssStatusProvider getGnssStatusProvider() {
433 return mGnssStatusProvider;
436 public IGpsGeofenceHardware getGpsGeofenceProxy() {
437 return mGpsGeofenceBinder;
440 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
441 return mGnssMeasurementsProvider;
444 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
445 return mGnssNavigationMessageProvider;
449 * Callback used to listen for data connectivity changes.
451 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
452 new ConnectivityManager.NetworkCallback() {
454 public void onAvailable(Network network) {
456 xtraDownloadRequest();
461 * Callback used to listen for availability of a requested SUPL connection.
462 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
463 * manage the registration/un-registration lifetimes separate.
465 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
466 new ConnectivityManager.NetworkCallback() {
468 public void onAvailable(Network network) {
469 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
473 public void onLost(Network network) {
474 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
478 public void onUnavailable() {
479 // timeout, it was not possible to establish the required connection
480 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
484 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
485 @Override public void onReceive(Context context, Intent intent) {
486 String action = intent.getAction();
487 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
488 if (action == null) {
492 if (action.equals(ALARM_WAKEUP)) {
493 startNavigating(false);
494 } else if (action.equals(ALARM_TIMEOUT)) {
496 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
497 checkSmsSuplInit(intent);
498 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
499 checkWapSuplInit(intent);
500 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
501 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
502 || Intent.ACTION_SCREEN_OFF.equals(action)
503 || Intent.ACTION_SCREEN_ON.equals(action)) {
504 updateLowPowerMode();
505 } else if (action.equals(SIM_STATE_CHANGED)) {
506 subscriptionOrSimChanged(context);
511 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
512 new OnSubscriptionsChangedListener() {
514 public void onSubscriptionsChanged() {
515 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
519 private final boolean isVerizon(String mccMnc, String imsi, String groupId) {
520 if (DEBUG) Log.d(TAG, "simOperator: " + mccMnc);
521 if (!TextUtils.isEmpty(mccMnc) || !TextUtils.isEmpty(imsi)) {
522 for (int i = 0; i < VzwMccMncList.length; i++) {
523 if ((!TextUtils.isEmpty(mccMnc) && mccMnc.equals(VzwMccMncList[i])) ||
524 (!TextUtils.isEmpty(imsi) && imsi.startsWith(VzwMccMncList[i]))) {
525 // check gid too if needed
526 if (TextUtils.isEmpty(VzwGid1List[i]) || VzwGid1List[i].equals(groupId)) {
527 if (DEBUG) Log.d(TAG, "Verizon UICC");
536 private void subscriptionOrSimChanged(Context context) {
537 if (DEBUG) Log.d(TAG, "received SIM related action: ");
538 TelephonyManager phone = (TelephonyManager)
539 mContext.getSystemService(Context.TELEPHONY_SERVICE);
540 String mccMnc = phone.getSimOperator();
541 String imsi = phone.getSubscriberId();
542 String groupId = phone.getGroupIdLevel1();
543 if (!TextUtils.isEmpty(mccMnc)) {
544 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
545 synchronized (mLock) {
546 if (isVerizon(mccMnc, imsi, groupId)) {
547 // load current properties for carrier VZW
548 loadPropertiesFromResource(context, mProperties);
549 String lpp_profile = mProperties.getProperty("LPP_PROFILE");
550 // set the persist property LPP_PROFILE for VZW
551 SystemProperties.set(LPP_PROFILE, lpp_profile);
553 // reset the persist property for Non VZW
554 SystemProperties.set(LPP_PROFILE, "");
556 reloadGpsProperties(context, mProperties);
557 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
560 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
564 private void checkSmsSuplInit(Intent intent) {
565 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
566 if (messages == null) {
567 Log.e(TAG, "Message does not exist in the intent.");
571 for (SmsMessage message : messages) {
572 if (message != null && message.mWrappedSmsMessage != null) {
573 byte[] suplInit = message.getUserData();
574 if (suplInit != null) {
575 native_agps_ni_message(suplInit, suplInit.length);
581 private void checkWapSuplInit(Intent intent) {
582 byte[] suplInit = intent.getByteArrayExtra("data");
583 if (suplInit == null) {
586 native_agps_ni_message(suplInit,suplInit.length);
589 private void updateLowPowerMode() {
590 // Disable GPS if we are in device idle mode.
591 boolean disableGps = mPowerManager.isDeviceIdleMode();
592 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
593 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
594 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
595 // If we are in battery saver mode and the screen is off, disable GPS.
596 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
599 if (disableGps != mDisableGps) {
600 mDisableGps = disableGps;
601 updateRequirements();
605 public static boolean isSupported() {
606 return native_is_supported();
609 private void reloadGpsProperties(Context context, Properties properties) {
610 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
611 loadPropertiesFromResource(context, properties);
613 boolean isPropertiesLoadedFromFile = false;
614 final String gpsHardware = SystemProperties.get("ro.hardware.gps");
616 if (!TextUtils.isEmpty(gpsHardware)) {
617 final String propFilename =
618 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
619 isPropertiesLoadedFromFile =
620 loadPropertiesFromFile(propFilename, properties);
622 if (!isPropertiesLoadedFromFile) {
623 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
625 if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
626 String lpp_prof = SystemProperties.get(LPP_PROFILE);
627 if (!TextUtils.isEmpty(lpp_prof)) {
628 // override default value of this if lpp_prof is not empty
629 properties.setProperty("LPP_PROFILE", lpp_prof);
631 // TODO: we should get rid of C2K specific setting.
632 setSuplHostPort(properties.getProperty("SUPL_HOST"),
633 properties.getProperty("SUPL_PORT"));
634 mC2KServerHost = properties.getProperty("C2K_HOST");
635 String portString = properties.getProperty("C2K_PORT");
636 if (mC2KServerHost != null && portString != null) {
638 mC2KServerPort = Integer.parseInt(portString);
639 } catch (NumberFormatException e) {
640 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
644 if (native_is_gnss_configuration_supported()) {
646 // Convert properties to string contents and send it to HAL.
647 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
648 properties.store(baos, null);
649 native_configuration_update(baos.toString());
650 if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
651 } catch (IOException ex) {
652 Log.e(TAG, "failed to dump properties contents");
655 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
659 // SUPL_ES configuration.
660 String suplESProperty = mProperties.getProperty("SUPL_ES");
661 if (suplESProperty != null) {
663 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
664 } catch (NumberFormatException e) {
665 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
670 private void loadPropertiesFromResource(Context context,
671 Properties properties) {
672 String[] configValues = context.getResources().getStringArray(
673 com.android.internal.R.array.config_gpsParameters);
674 for (String item : configValues) {
675 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
676 // We need to support "KEY =", but not "=VALUE".
677 String[] split = item.split("=");
678 if (split.length == 2) {
679 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
681 Log.w(TAG, "malformed contents: " + item);
686 private boolean loadPropertiesFromFile(String filename,
687 Properties properties) {
689 File file = new File(filename);
690 FileInputStream stream = null;
692 stream = new FileInputStream(file);
693 properties.load(stream);
695 IoUtils.closeQuietly(stream);
698 } catch (IOException e) {
699 Log.w(TAG, "Could not open GPS configuration file " + filename);
705 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
708 mNtpTime = NtpTrustedTime.getInstance(context);
709 mILocationManager = ilocationManager;
711 mLocation.setExtras(mLocationExtras);
713 // Create a wake lock
714 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
715 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
716 mWakeLock.setReferenceCounted(true);
718 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
719 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
720 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
722 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
724 // App ops service to keep track of who is accessing the GPS
725 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
726 Context.APP_OPS_SERVICE));
728 // Battery statistics service to be notified when GPS turns on or off
729 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
730 BatteryStats.SERVICE_NAME));
732 // Construct internal handler
733 mHandler = new ProviderHandler(looper);
735 // Load GPS configuration and register listeners in the background:
736 // some operations, such as opening files and registering broadcast receivers, can take a
737 // relative long time, so the ctor() is kept to create objects needed by this instance,
738 // while IO initialization and registration is delegated to our internal handler
739 // this approach is just fine because events are posted to our handler anyway
740 mProperties = new Properties();
741 sendMessage(INITIALIZE_HANDLER, 0, null);
743 // Create a GPS net-initiated handler.
744 mNIHandler = new GpsNetInitiatedHandler(context,
745 mNetInitiatedListener,
748 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
750 protected boolean isAvailableInPlatform() {
751 return isSupported();
755 protected boolean isGpsEnabled() {
760 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
762 public boolean isAvailableInPlatform() {
763 return native_is_measurement_supported();
767 protected boolean registerWithService() {
768 return native_start_measurement_collection();
772 protected void unregisterFromService() {
773 native_stop_measurement_collection();
777 protected boolean isGpsEnabled() {
782 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
784 protected boolean isAvailableInPlatform() {
785 return native_is_navigation_message_supported();
789 protected boolean registerWithService() {
790 return native_start_navigation_message_collection();
794 protected void unregisterFromService() {
795 native_stop_navigation_message_collection();
799 protected boolean isGpsEnabled() {
806 * Returns the name of this provider.
809 public String getName() {
810 return LocationManager.GPS_PROVIDER;
814 public ProviderProperties getProperties() {
818 private void handleUpdateNetworkState(Network network) {
819 // retrieve NetworkInfo for this UID
820 NetworkInfo info = mConnMgr.getNetworkInfo(network);
825 boolean isConnected = info.isConnected();
827 String message = String.format(
828 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
829 agpsDataConnStateAsString(),
832 mConnMgr.getNetworkCapabilities(network));
836 if (native_is_agps_ril_supported()) {
837 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
838 boolean networkAvailable = info.isAvailable() && dataEnabled;
839 String defaultApn = getSelectedApn();
840 if (defaultApn == null) {
841 defaultApn = "dummy-apn";
844 native_update_network_state(
852 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
855 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
857 String apnName = info.getExtraInfo();
858 if (apnName == null) {
859 // assign a dummy value in the case of C2K as otherwise we will have a runtime
860 // exception in the following call to native_agps_data_conn_open
861 apnName = "dummy-apn";
863 int apnIpType = getApnIpType(apnName);
866 String message = String.format(
867 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
872 native_agps_data_conn_open(apnName, apnIpType);
873 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
875 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
880 private void handleRequestSuplConnection(InetAddress address) {
882 String message = String.format(
883 "requestSuplConnection, state=%s, address=%s",
884 agpsDataConnStateAsString(),
889 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
892 mAGpsDataConnectionIpAddr = address;
893 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
895 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
896 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
897 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
898 NetworkRequest request = requestBuilder.build();
899 mConnMgr.requestNetwork(
901 mSuplConnectivityCallback,
902 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
905 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
907 String message = String.format(
908 "releaseSuplConnection, state=%s, status=%s",
909 agpsDataConnStateAsString(),
910 agpsDataConnStatusAsString(agpsDataConnStatus));
914 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
917 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
919 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
920 switch (agpsDataConnStatus) {
921 case GPS_AGPS_DATA_CONN_FAILED:
922 native_agps_data_conn_failed();
924 case GPS_RELEASE_AGPS_DATA_CONN:
925 native_agps_data_conn_closed();
928 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
932 private void handleInjectNtpTime() {
933 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
934 // already downloading data
937 if (!isDataNetworkConnected()) {
938 // try again when network is up
939 mInjectNtpTimePending = STATE_PENDING_NETWORK;
942 mInjectNtpTimePending = STATE_DOWNLOADING;
944 // hold wake lock while task runs
946 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
947 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
952 // force refresh NTP cache when outdated
953 boolean refreshSuccess = true;
954 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
955 refreshSuccess = mNtpTime.forceRefresh();
958 // only update when NTP time is fresh
959 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
960 long time = mNtpTime.getCachedNtpTime();
961 long timeReference = mNtpTime.getCachedNtpTimeReference();
962 long certainty = mNtpTime.getCacheCertainty();
963 long now = System.currentTimeMillis();
966 Log.d(TAG, "NTP server returned: "
967 + time + " (" + new Date(time)
968 + ") reference: " + timeReference
969 + " certainty: " + certainty
970 + " system time offset: " + (time - now));
973 native_inject_time(time, timeReference, (int) certainty);
974 delay = NTP_INTERVAL;
977 Log.e(TAG, "requestTime failed");
978 delay = mNtpBackOff.nextBackoffMillis();
981 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
984 String message = String.format(
985 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
986 mOnDemandTimeInjection,
991 if (mOnDemandTimeInjection || !refreshSuccess) {
992 // send delayed message for next NTP injection
993 // since this is delayed and not urgent we do not hold a wake lock here
994 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
997 // release wake lock held by task
999 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1004 private void handleDownloadXtraData() {
1005 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1006 // already downloading data
1009 if (!isDataNetworkConnected()) {
1010 // try again when network is up
1011 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1014 mDownloadXtraDataPending = STATE_DOWNLOADING;
1016 // hold wake lock while task runs
1017 mWakeLock.acquire();
1018 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1019 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1022 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1023 byte[] data = xtraDownloader.downloadXtraData();
1025 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1026 native_inject_xtra_data(data, data.length);
1027 mXtraBackOff.reset();
1030 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1034 // since this is delayed and not urgent we do not hold a wake lock here
1035 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1036 mXtraBackOff.nextBackoffMillis());
1039 // release wake lock held by task
1040 mWakeLock.release();
1041 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1046 private void handleUpdateLocation(Location location) {
1047 if (location.hasAccuracy()) {
1048 native_inject_location(location.getLatitude(), location.getLongitude(),
1049 location.getAccuracy());
1054 * Enables this provider. When enabled, calls to getStatus()
1055 * must be handled. Hardware may be started up
1056 * when the provider is enabled.
1059 public void enable() {
1060 synchronized (mLock) {
1061 if (mEnabled) return;
1065 sendMessage(ENABLE, 1, null);
1068 private void setSuplHostPort(String hostString, String portString) {
1069 if (hostString != null) {
1070 mSuplServerHost = hostString;
1072 if (portString != null) {
1074 mSuplServerPort = Integer.parseInt(portString);
1075 } catch (NumberFormatException e) {
1076 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1079 if (mSuplServerHost != null
1080 && mSuplServerPort > TCP_MIN_PORT
1081 && mSuplServerPort <= TCP_MAX_PORT) {
1082 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1087 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1088 * allowed mode from properties.
1090 * @param properties GPS properties
1091 * @param agpsEnabled whether AGPS is enabled by settings value
1092 * @param singleShot whether "singleshot" is needed
1093 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1095 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1097 String modeString = properties.getProperty("SUPL_MODE");
1099 if (!TextUtils.isEmpty(modeString)) {
1101 suplMode = Integer.parseInt(modeString);
1102 } catch (NumberFormatException e) {
1103 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1104 return GPS_POSITION_MODE_STANDALONE;
1107 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1108 // such mode when it is available
1109 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1110 return GPS_POSITION_MODE_MS_BASED;
1112 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1113 // do fallback only for single-shot requests, because it is too expensive to do for
1114 // periodic requests as well
1116 && hasCapability(GPS_CAPABILITY_MSA)
1117 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1118 return GPS_POSITION_MODE_MS_ASSISTED;
1121 return GPS_POSITION_MODE_STANDALONE;
1124 private void handleEnable() {
1125 if (DEBUG) Log.d(TAG, "handleEnable");
1127 boolean enabled = native_init();
1130 mSupportsXtra = native_supports_xtra();
1132 // TODO: remove the following native calls if we can make sure they are redundant.
1133 if (mSuplServerHost != null) {
1134 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1136 if (mC2KServerHost != null) {
1137 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1140 mGnssMeasurementsProvider.onGpsEnabledChanged();
1141 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1143 synchronized (mLock) {
1146 Log.w(TAG, "Failed to enable location provider");
1151 * Disables this provider. When disabled, calls to getStatus()
1152 * need not be handled. Hardware may be shut
1153 * down while the provider is disabled.
1156 public void disable() {
1157 synchronized (mLock) {
1158 if (!mEnabled) return;
1162 sendMessage(ENABLE, 0, null);
1165 private void handleDisable() {
1166 if (DEBUG) Log.d(TAG, "handleDisable");
1168 updateClientUids(new WorkSource());
1170 mAlarmManager.cancel(mWakeupIntent);
1171 mAlarmManager.cancel(mTimeoutIntent);
1173 // do this before releasing wakelock
1176 mGnssMeasurementsProvider.onGpsEnabledChanged();
1177 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1181 public boolean isEnabled() {
1182 synchronized (mLock) {
1188 public int getStatus(Bundle extras) {
1189 if (extras != null) {
1190 extras.putInt("satellites", mSvCount);
1195 private void updateStatus(int status, int svCount) {
1196 if (status != mStatus || svCount != mSvCount) {
1199 mLocationExtras.putInt("satellites", svCount);
1200 mStatusUpdateTime = SystemClock.elapsedRealtime();
1205 public long getStatusUpdateTime() {
1206 return mStatusUpdateTime;
1210 public void setRequest(ProviderRequest request, WorkSource source) {
1211 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1214 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1215 mProviderRequest = request;
1216 mWorkSource = source;
1217 updateRequirements();
1220 // Called when the requirements for GPS may have changed
1221 private void updateRequirements() {
1222 if (mProviderRequest == null || mWorkSource == null) {
1226 boolean singleShot = false;
1228 // see if the request is for a single update
1229 if (mProviderRequest.locationRequests != null
1230 && mProviderRequest.locationRequests.size() > 0) {
1231 // if any request has zero or more than one updates
1232 // requested, then this is not single-shot mode
1235 for (LocationRequest lr : mProviderRequest.locationRequests) {
1236 if (lr.getNumUpdates() != 1) {
1242 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1243 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1244 // update client uids
1245 updateClientUids(mWorkSource);
1247 mFixInterval = (int) mProviderRequest.interval;
1249 // check for overflow
1250 if (mFixInterval != mProviderRequest.interval) {
1251 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1252 mFixInterval = Integer.MAX_VALUE;
1255 // apply request to GPS engine
1256 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1258 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1259 mFixInterval, 0, 0)) {
1260 Log.e(TAG, "set_position_mode failed in setMinTime()");
1262 } else if (!mStarted) {
1264 startNavigating(singleShot);
1267 updateClientUids(new WorkSource());
1270 mAlarmManager.cancel(mWakeupIntent);
1271 mAlarmManager.cancel(mTimeoutIntent);
1275 private void updateClientUids(WorkSource source) {
1276 // Update work source.
1277 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1278 if (changes == null) {
1281 WorkSource newWork = changes[0];
1282 WorkSource goneWork = changes[1];
1284 // Update sources that were not previously tracked.
1285 if (newWork != null) {
1287 for (int i=0; i<newWork.size(); i++) {
1289 int uid = newWork.get(i);
1290 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1291 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1292 if (uid != lastuid) {
1294 mBatteryStats.noteStartGps(uid);
1296 } catch (RemoteException e) {
1297 Log.w(TAG, "RemoteException", e);
1302 // Update sources that are no longer tracked.
1303 if (goneWork != null) {
1305 for (int i=0; i<goneWork.size(); i++) {
1307 int uid = goneWork.get(i);
1308 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1309 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1310 if (uid != lastuid) {
1312 mBatteryStats.noteStopGps(uid);
1314 } catch (RemoteException e) {
1315 Log.w(TAG, "RemoteException", e);
1322 public boolean sendExtraCommand(String command, Bundle extras) {
1324 long identity = Binder.clearCallingIdentity();
1325 boolean result = false;
1327 if ("delete_aiding_data".equals(command)) {
1328 result = deleteAidingData(extras);
1329 } else if ("force_time_injection".equals(command)) {
1332 } else if ("force_xtra_injection".equals(command)) {
1333 if (mSupportsXtra) {
1334 xtraDownloadRequest();
1338 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1341 Binder.restoreCallingIdentity(identity);
1345 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1346 public boolean isHardwareGeofenceSupported() {
1347 return native_is_geofence_supported();
1350 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1351 double longitude, double radius, int lastTransition, int monitorTransitions,
1352 int notificationResponsiveness, int unknownTimer) {
1353 return native_add_geofence(geofenceId, latitude, longitude, radius,
1354 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1357 public boolean removeHardwareGeofence(int geofenceId) {
1358 return native_remove_geofence(geofenceId);
1361 public boolean pauseHardwareGeofence(int geofenceId) {
1362 return native_pause_geofence(geofenceId);
1365 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1366 return native_resume_geofence(geofenceId, monitorTransition);
1370 private boolean deleteAidingData(Bundle extras) {
1373 if (extras == null) {
1374 flags = GPS_DELETE_ALL;
1377 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1378 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1379 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1380 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1381 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1382 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1383 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1384 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1385 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1386 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1387 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1388 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1389 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1393 native_delete_aiding_data(flags);
1400 private void startNavigating(boolean singleShot) {
1402 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1403 mTimeToFirstFix = 0;
1406 mSingleShot = singleShot;
1407 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1409 boolean agpsEnabled =
1410 (Settings.Global.getInt(mContext.getContentResolver(),
1411 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1412 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1417 switch(mPositionMode) {
1418 case GPS_POSITION_MODE_STANDALONE:
1419 mode = "standalone";
1421 case GPS_POSITION_MODE_MS_ASSISTED:
1422 mode = "MS_ASSISTED";
1424 case GPS_POSITION_MODE_MS_BASED:
1431 Log.d(TAG, "setting position_mode to " + mode);
1434 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1435 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1438 Log.e(TAG, "set_position_mode failed in startNavigating()");
1441 if (!native_start()) {
1443 Log.e(TAG, "native_start failed in startNavigating()");
1447 // reset SV count to zero
1448 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1449 mFixRequestTime = System.currentTimeMillis();
1450 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1451 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1452 // and our fix interval is not short
1453 if (mFixInterval >= NO_FIX_TIMEOUT) {
1454 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1455 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1461 private void stopNavigating() {
1462 if (DEBUG) Log.d(TAG, "stopNavigating");
1465 mSingleShot = false;
1467 mTimeToFirstFix = 0;
1469 mLocationFlags = LOCATION_INVALID;
1471 // reset SV count to zero
1472 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1476 private void hibernate() {
1477 // stop GPS until our next fix interval arrives
1479 mAlarmManager.cancel(mTimeoutIntent);
1480 mAlarmManager.cancel(mWakeupIntent);
1481 long now = SystemClock.elapsedRealtime();
1482 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1485 private boolean hasCapability(int capability) {
1486 return ((mEngineCapabilities & capability) != 0);
1491 * called from native code to update our position.
1493 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1494 float speed, float bearing, float accuracy, long timestamp) {
1495 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1496 " timestamp: " + timestamp);
1498 synchronized (mLocation) {
1499 mLocationFlags = flags;
1500 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1501 mLocation.setLatitude(latitude);
1502 mLocation.setLongitude(longitude);
1503 mLocation.setTime(timestamp);
1504 // It would be nice to push the elapsed real-time timestamp
1505 // further down the stack, but this is still useful
1506 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1508 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1509 mLocation.setAltitude(altitude);
1511 mLocation.removeAltitude();
1513 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1514 mLocation.setSpeed(speed);
1516 mLocation.removeSpeed();
1518 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1519 mLocation.setBearing(bearing);
1521 mLocation.removeBearing();
1523 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1524 mLocation.setAccuracy(accuracy);
1526 mLocation.removeAccuracy();
1528 mLocation.setExtras(mLocationExtras);
1531 mILocationManager.reportLocation(mLocation, false);
1532 } catch (RemoteException e) {
1533 Log.e(TAG, "RemoteException calling reportLocation");
1537 mLastFixTime = System.currentTimeMillis();
1538 // report time to first fix
1539 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1540 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1541 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1543 // notify status listeners
1544 mListenerHelper.onFirstFix(mTimeToFirstFix);
1551 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1552 // we want to time out if we do not receive a fix
1553 // within the time out and we are requesting infrequent fixes
1554 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1555 mAlarmManager.cancel(mTimeoutIntent);
1558 // send an intent to notify that the GPS is receiving fixes.
1559 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1560 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1561 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1562 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1565 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1566 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1567 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1573 * called from native code to update our status
1575 private void reportStatus(int status) {
1576 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1578 boolean wasNavigating = mNavigating;
1580 case GPS_STATUS_SESSION_BEGIN:
1584 case GPS_STATUS_SESSION_END:
1585 mNavigating = false;
1587 case GPS_STATUS_ENGINE_ON:
1590 case GPS_STATUS_ENGINE_OFF:
1592 mNavigating = false;
1596 if (wasNavigating != mNavigating) {
1597 mListenerHelper.onStatusChanged(mNavigating);
1599 // send an intent to notify that the GPS has been enabled or disabled
1600 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1601 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1602 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1607 * called from native code to update SV info
1609 private void reportSvStatus() {
1610 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1611 mListenerHelper.onSvStatusChanged(
1619 Log.v(TAG, "SV count: " + svCount);
1621 // Calculate number of sets used in fix.
1622 int usedInFixCount = 0;
1623 for (int i = 0; i < svCount; i++) {
1624 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1628 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1629 " cn0: " + mCn0s[i]/10 +
1630 " elev: " + mSvElevations[i] +
1631 " azimuth: " + mSvAzimuths[i] +
1632 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1634 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1636 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1640 // return number of sets used in fix instead of total
1641 updateStatus(mStatus, usedInFixCount);
1643 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1644 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1645 // send an intent to notify that the GPS is no longer receiving fixes.
1646 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1647 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1648 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1649 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1654 * called from native code to update AGPS status
1656 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1658 case GPS_REQUEST_AGPS_DATA_CONN:
1659 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1660 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1661 InetAddress connectionIpAddress = null;
1662 if (ipaddr != null) {
1664 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1665 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1666 } catch (UnknownHostException e) {
1667 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1670 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1672 case GPS_RELEASE_AGPS_DATA_CONN:
1673 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1674 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1676 case GPS_AGPS_DATA_CONNECTED:
1677 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1679 case GPS_AGPS_DATA_CONN_DONE:
1680 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1682 case GPS_AGPS_DATA_CONN_FAILED:
1683 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1686 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1690 private void releaseSuplConnection(int connStatus) {
1691 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1695 * called from native code to report NMEA data received
1697 private void reportNmea(long timestamp) {
1698 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1699 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1700 mListenerHelper.onNmeaReceived(timestamp, nmea);
1704 * called from native code - Gps measurements callback
1706 private void reportMeasurementData(GnssMeasurementsEvent event) {
1707 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1711 * called from native code - GPS navigation message callback
1713 private void reportNavigationMessage(GnssNavigationMessage event) {
1714 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1718 * called from native code to inform us what the GPS engine capabilities are
1720 private void setEngineCapabilities(int capabilities) {
1721 mEngineCapabilities = capabilities;
1723 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1724 mOnDemandTimeInjection = true;
1728 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1729 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1730 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1731 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1735 * Called from native code to inform us the hardware information.
1737 private void setGnssYearOfHardware(int yearOfHardware) {
1738 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1739 mYearOfHardware = yearOfHardware;
1742 public interface GnssSystemInfoProvider {
1744 * Returns the year of GPS hardware.
1746 int getGnssYearOfHardware();
1752 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1753 return new GnssSystemInfoProvider() {
1755 public int getGnssYearOfHardware() {
1756 return mYearOfHardware;
1762 * called from native code to request XTRA data
1764 private void xtraDownloadRequest() {
1765 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1766 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1770 * Helper method to construct a location object.
1772 private Location buildLocation(
1781 Location location = new Location(LocationManager.GPS_PROVIDER);
1782 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1783 location.setLatitude(latitude);
1784 location.setLongitude(longitude);
1785 location.setTime(timestamp);
1786 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1788 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1789 location.setAltitude(altitude);
1791 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1792 location.setSpeed(speed);
1794 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1795 location.setBearing(bearing);
1797 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1798 location.setAccuracy(accuracy);
1804 * Converts the GPS HAL status to the internal Geofence Hardware status.
1806 private int getGeofenceStatus(int status) {
1808 case GPS_GEOFENCE_OPERATION_SUCCESS:
1809 return GeofenceHardware.GEOFENCE_SUCCESS;
1810 case GPS_GEOFENCE_ERROR_GENERIC:
1811 return GeofenceHardware.GEOFENCE_FAILURE;
1812 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1813 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1814 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1815 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1816 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1817 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1818 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1819 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1826 * Called from native to report GPS Geofence transition
1827 * All geofence callbacks are called on the same thread
1829 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1830 double longitude, double altitude, float speed, float bearing, float accuracy,
1831 long timestamp, int transition, long transitionTimestamp) {
1832 if (mGeofenceHardwareImpl == null) {
1833 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1835 Location location = buildLocation(
1844 mGeofenceHardwareImpl.reportGeofenceTransition(
1848 transitionTimestamp,
1849 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1850 FusedBatchOptions.SourceTechnologies.GNSS);
1854 * called from native code to report GPS status change.
1856 private void reportGeofenceStatus(int status, int flags, double latitude,
1857 double longitude, double altitude, float speed, float bearing, float accuracy,
1859 if (mGeofenceHardwareImpl == null) {
1860 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1862 Location location = buildLocation(
1871 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1872 if(status == GPS_GEOFENCE_AVAILABLE) {
1873 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1875 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1876 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1879 FusedBatchOptions.SourceTechnologies.GNSS);
1883 * called from native code - Geofence Add callback
1885 private void reportGeofenceAddStatus(int geofenceId, int status) {
1886 if (mGeofenceHardwareImpl == null) {
1887 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1889 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1893 * called from native code - Geofence Remove callback
1895 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1896 if (mGeofenceHardwareImpl == null) {
1897 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1899 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1903 * called from native code - Geofence Pause callback
1905 private void reportGeofencePauseStatus(int geofenceId, int status) {
1906 if (mGeofenceHardwareImpl == null) {
1907 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1909 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1913 * called from native code - Geofence Resume callback
1915 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1916 if (mGeofenceHardwareImpl == null) {
1917 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1919 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1922 //=============================================================
1923 // NI Client support
1924 //=============================================================
1925 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1926 // Sends a response for an NI request to HAL.
1928 public boolean sendNiResponse(int notificationId, int userResponse)
1930 // TODO Add Permission check
1932 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1933 ", response: " + userResponse);
1934 native_send_ni_response(notificationId, userResponse);
1939 public INetInitiatedListener getNetInitiatedListener() {
1940 return mNetInitiatedListener;
1943 // Called by JNI function to report an NI request.
1944 public void reportNiNotification(
1949 int defaultResponse,
1952 int requestorIdEncoding,
1954 String extras // Encoded extra data
1957 Log.i(TAG, "reportNiNotification: entered");
1958 Log.i(TAG, "notificationId: " + notificationId +
1959 ", niType: " + niType +
1960 ", notifyFlags: " + notifyFlags +
1961 ", timeout: " + timeout +
1962 ", defaultResponse: " + defaultResponse);
1964 Log.i(TAG, "requestorId: " + requestorId +
1966 ", requestorIdEncoding: " + requestorIdEncoding +
1967 ", textEncoding: " + textEncoding);
1969 GpsNiNotification notification = new GpsNiNotification();
1971 notification.notificationId = notificationId;
1972 notification.niType = niType;
1973 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1974 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1975 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1976 notification.timeout = timeout;
1977 notification.defaultResponse = defaultResponse;
1978 notification.requestorId = requestorId;
1979 notification.text = text;
1980 notification.requestorIdEncoding = requestorIdEncoding;
1981 notification.textEncoding = textEncoding;
1983 // Process extras, assuming the format is
1984 // one of more lines of "key = value"
1985 Bundle bundle = new Bundle();
1987 if (extras == null) extras = "";
1988 Properties extraProp = new Properties();
1991 extraProp.load(new StringReader(extras));
1993 catch (IOException e)
1995 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1998 for (Entry<Object, Object> ent : extraProp.entrySet())
2000 bundle.putString((String) ent.getKey(), (String) ent.getValue());
2003 notification.extras = bundle;
2005 mNIHandler.handleNiNotification(notification);
2009 * Called from native code to request set id info.
2010 * We should be careful about receiving null string from the TelephonyManager,
2011 * because sending null String to JNI function would cause a crash.
2014 private void requestSetID(int flags) {
2015 TelephonyManager phone = (TelephonyManager)
2016 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2017 int type = AGPS_SETID_TYPE_NONE;
2020 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2021 String data_temp = phone.getSubscriberId();
2022 if (data_temp == null) {
2023 // This means the framework does not have the SIM card ready.
2025 // This means the framework has the SIM card.
2027 type = AGPS_SETID_TYPE_IMSI;
2030 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2031 String data_temp = phone.getLine1Number();
2032 if (data_temp == null) {
2033 // This means the framework does not have the SIM card ready.
2035 // This means the framework has the SIM card.
2037 type = AGPS_SETID_TYPE_MSISDN;
2040 native_agps_set_id(type, data);
2044 * Called from native code to request utc time info
2046 private void requestUtcTime() {
2047 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2048 sendMessage(INJECT_NTP_TIME, 0, null);
2052 * Called from native code to request reference location info
2055 private void requestRefLocation(int flags) {
2056 TelephonyManager phone = (TelephonyManager)
2057 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2058 final int phoneType = phone.getPhoneType();
2059 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2060 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2061 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2062 && (phone.getNetworkOperator().length() > 3)) {
2064 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2065 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2066 int networkType = phone.getNetworkType();
2067 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2068 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2069 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2070 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2071 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2072 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2074 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2076 native_agps_set_ref_location_cellid(type, mcc, mnc,
2077 gsm_cell.getLac(), gsm_cell.getCid());
2079 Log.e(TAG,"Error getting cell location info.");
2081 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2082 Log.e(TAG, "CDMA not supported.");
2086 private void sendMessage(int message, int arg, Object obj) {
2087 // hold a wake lock until this message is delivered
2088 // note that this assumes the message will not be removed from the queue before
2089 // it is handled (otherwise the wake lock would be leaked).
2090 mWakeLock.acquire();
2091 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2092 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2095 private final class ProviderHandler extends Handler {
2096 public ProviderHandler(Looper looper) {
2097 super(looper, null, true /*async*/);
2101 public void handleMessage(Message msg) {
2102 int message = msg.what;
2105 if (msg.arg1 == 1) {
2112 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2113 handleSetRequest(gpsRequest.request, gpsRequest.source);
2115 case UPDATE_NETWORK_STATE:
2116 handleUpdateNetworkState((Network) msg.obj);
2118 case REQUEST_SUPL_CONNECTION:
2119 handleRequestSuplConnection((InetAddress) msg.obj);
2121 case RELEASE_SUPL_CONNECTION:
2122 handleReleaseSuplConnection(msg.arg1);
2124 case INJECT_NTP_TIME:
2125 handleInjectNtpTime();
2127 case DOWNLOAD_XTRA_DATA:
2128 if (mSupportsXtra) {
2129 handleDownloadXtraData();
2132 case INJECT_NTP_TIME_FINISHED:
2133 mInjectNtpTimePending = STATE_IDLE;
2135 case DOWNLOAD_XTRA_DATA_FINISHED:
2136 mDownloadXtraDataPending = STATE_IDLE;
2138 case UPDATE_LOCATION:
2139 handleUpdateLocation((Location) msg.obj);
2141 case SUBSCRIPTION_OR_SIM_CHANGED:
2142 subscriptionOrSimChanged(mContext);
2144 case INITIALIZE_HANDLER:
2148 if (msg.arg2 == 1) {
2149 // wakelock was taken for this message, release it
2150 mWakeLock.release();
2151 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2157 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2158 * It is in charge of loading properties and registering for events that will be posted to
2161 private void handleInitialize() {
2162 // load default GPS configuration
2163 // (this configuration might change in the future based on SIM changes)
2164 reloadGpsProperties(mContext, mProperties);
2166 // TODO: When this object "finishes" we should unregister by invoking
2167 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2168 // This is not strictly necessary because it will be unregistered if the
2169 // notification fails but it is good form.
2171 // Register for SubscriptionInfo list changes which is guaranteed
2172 // to invoke onSubscriptionsChanged the first time.
2173 SubscriptionManager.from(mContext)
2174 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2176 // listen for events
2177 IntentFilter intentFilter;
2178 if (native_is_agps_ril_supported()) {
2179 intentFilter = new IntentFilter();
2180 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2181 intentFilter.addDataScheme("sms");
2182 intentFilter.addDataAuthority("localhost", "7275");
2183 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2185 intentFilter = new IntentFilter();
2186 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2188 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2189 } catch (IntentFilter.MalformedMimeTypeException e) {
2190 Log.w(TAG, "Malformed SUPL init mime type");
2192 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2194 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2195 + " HAL is not supported");
2198 intentFilter = new IntentFilter();
2199 intentFilter.addAction(ALARM_WAKEUP);
2200 intentFilter.addAction(ALARM_TIMEOUT);
2201 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2202 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2203 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2204 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2205 intentFilter.addAction(SIM_STATE_CHANGED);
2206 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2208 // register for connectivity change events, this is equivalent to the deprecated way of
2209 // registering for CONNECTIVITY_ACTION broadcasts
2210 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2211 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2212 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2213 NetworkRequest networkRequest = networkRequestBuilder.build();
2214 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2216 // listen for PASSIVE_PROVIDER updates
2217 LocationManager locManager =
2218 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2220 float minDistance = 0;
2221 boolean oneShot = false;
2222 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2223 LocationManager.PASSIVE_PROVIDER,
2227 // Don't keep track of this request since it's done on behalf of other clients
2228 // (which are kept track of separately).
2229 request.setHideFromAppOps(true);
2230 locManager.requestLocationUpdates(
2232 new NetworkLocationListener(),
2237 private final class NetworkLocationListener implements LocationListener {
2239 public void onLocationChanged(Location location) {
2240 // this callback happens on mHandler looper
2241 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2242 handleUpdateLocation(location);
2246 public void onStatusChanged(String provider, int status, Bundle extras) { }
2248 public void onProviderEnabled(String provider) { }
2250 public void onProviderDisabled(String provider) { }
2253 private String getSelectedApn() {
2254 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2255 Cursor cursor = null;
2257 cursor = mContext.getContentResolver().query(
2259 new String[] { "apn" },
2260 null /* selection */,
2261 null /* selectionArgs */,
2262 Carriers.DEFAULT_SORT_ORDER);
2263 if (cursor != null && cursor.moveToFirst()) {
2264 return cursor.getString(0);
2266 Log.e(TAG, "No APN found to select.");
2268 } catch (Exception e) {
2269 Log.e(TAG, "Error encountered on selecting the APN.", e);
2271 if (cursor != null) {
2279 private int getApnIpType(String apn) {
2280 ensureInHandlerThread();
2285 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2286 Cursor cursor = null;
2288 cursor = mContext.getContentResolver().query(
2289 Carriers.CONTENT_URI,
2290 new String[] { Carriers.PROTOCOL },
2293 Carriers.DEFAULT_SORT_ORDER);
2295 if (null != cursor && cursor.moveToFirst()) {
2296 return translateToApnIpType(cursor.getString(0), apn);
2298 Log.e(TAG, "No entry found in query for APN: " + apn);
2300 } catch (Exception e) {
2301 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2303 if (cursor != null) {
2311 private int translateToApnIpType(String ipProtocol, String apn) {
2312 if ("IP".equals(ipProtocol)) {
2315 if ("IPV6".equals(ipProtocol)) {
2318 if ("IPV4V6".equals(ipProtocol)) {
2322 // we hit the default case so the ipProtocol is not recognized
2323 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2324 Log.e(TAG, message);
2328 private void setRouting() {
2329 if (mAGpsDataConnectionIpAddr == null) {
2333 // TODO: replace the use of this deprecated API
2334 boolean result = mConnMgr.requestRouteToHostAddress(
2335 ConnectivityManager.TYPE_MOBILE_SUPL,
2336 mAGpsDataConnectionIpAddr);
2339 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2341 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2346 * @return {@code true} if there is a data network available for outgoing connections,
2347 * {@code false} otherwise.
2349 private boolean isDataNetworkConnected() {
2350 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2351 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2355 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2357 private void ensureInHandlerThread() {
2358 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2361 throw new RuntimeException("This method must run on the Handler thread.");
2365 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2367 private String agpsDataConnStateAsString() {
2368 switch(mAGpsDataConnectionState) {
2369 case AGPS_DATA_CONNECTION_CLOSED:
2371 case AGPS_DATA_CONNECTION_OPEN:
2373 case AGPS_DATA_CONNECTION_OPENING:
2381 * @return A string representing the given GPS_AGPS_DATA status.
2383 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2384 switch (agpsDataConnStatus) {
2385 case GPS_AGPS_DATA_CONNECTED:
2387 case GPS_AGPS_DATA_CONN_DONE:
2389 case GPS_AGPS_DATA_CONN_FAILED:
2391 case GPS_RELEASE_AGPS_DATA_CONN:
2393 case GPS_REQUEST_AGPS_DATA_CONN:
2401 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2402 StringBuilder s = new StringBuilder();
2403 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2404 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2405 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2407 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2408 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2409 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2410 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2411 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2412 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2413 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2414 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2417 s.append(native_get_internal_state());
2422 * A simple implementation of exponential backoff.
2424 private static final class BackOff {
2425 private static final int MULTIPLIER = 2;
2426 private final long mInitIntervalMillis;
2427 private final long mMaxIntervalMillis;
2428 private long mCurrentIntervalMillis;
2430 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2431 mInitIntervalMillis = initIntervalMillis;
2432 mMaxIntervalMillis = maxIntervalMillis;
2434 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2437 public long nextBackoffMillis() {
2438 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2439 return mMaxIntervalMillis;
2442 mCurrentIntervalMillis *= MULTIPLIER;
2443 return mCurrentIntervalMillis;
2446 public void reset() {
2447 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2451 // for GPS SV statistics
2452 private static final int MAX_SVS = 64;
2454 // preallocated arrays, to avoid memory allocation in reportStatus()
2455 private int mSvidWithFlags[] = new int[MAX_SVS];
2456 private float mCn0s[] = new float[MAX_SVS];
2457 private float mSvElevations[] = new float[MAX_SVS];
2458 private float mSvAzimuths[] = new float[MAX_SVS];
2459 private int mSvCount;
2460 // preallocated to avoid memory allocation in reportNmea()
2461 private byte[] mNmeaBuffer = new byte[120];
2463 static { class_init_native(); }
2464 private static native void class_init_native();
2465 private static native boolean native_is_supported();
2466 private static native boolean native_is_agps_ril_supported();
2467 private static native boolean native_is_gnss_configuration_supported();
2469 private native boolean native_init();
2470 private native void native_cleanup();
2471 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2472 int preferred_accuracy, int preferred_time);
2473 private native boolean native_start();
2474 private native boolean native_stop();
2475 private native void native_delete_aiding_data(int flags);
2476 // returns number of SVs
2477 // mask[0] is ephemeris mask and mask[1] is almanac mask
2478 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2480 private native int native_read_nmea(byte[] buffer, int bufferSize);
2481 private native void native_inject_location(double latitude, double longitude, float accuracy);
2484 private native void native_inject_time(long time, long timeReference, int uncertainty);
2485 private native boolean native_supports_xtra();
2486 private native void native_inject_xtra_data(byte[] data, int length);
2489 private native String native_get_internal_state();
2492 private native void native_agps_data_conn_open(String apn, int apnIpType);
2493 private native void native_agps_data_conn_closed();
2494 private native void native_agps_data_conn_failed();
2495 private native void native_agps_ni_message(byte [] msg, int length);
2496 private native void native_set_agps_server(int type, String hostname, int port);
2498 // Network-initiated (NI) Support
2499 private native void native_send_ni_response(int notificationId, int userResponse);
2502 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2504 private native void native_agps_set_id(int type, String setid);
2506 private native void native_update_network_state(boolean connected, int type,
2507 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2509 // Hardware Geofence support.
2510 private static native boolean native_is_geofence_supported();
2511 private static native boolean native_add_geofence(int geofenceId, double latitude,
2512 double longitude, double radius, int lastTransition,int monitorTransitions,
2513 int notificationResponsivenes, int unknownTimer);
2514 private static native boolean native_remove_geofence(int geofenceId);
2515 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2516 private static native boolean native_pause_geofence(int geofenceId);
2518 // Gps Hal measurements support.
2519 private static native boolean native_is_measurement_supported();
2520 private native boolean native_start_measurement_collection();
2521 private native boolean native_stop_measurement_collection();
2523 // Gps Navigation message support.
2524 private static native boolean native_is_navigation_message_supported();
2525 private native boolean native_start_navigation_message_collection();
2526 private native boolean native_stop_navigation_message_collection();
2528 // GNSS Configuration
2529 private static native void native_configuration_update(String configData);