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 // Set lower than the current ITAR limit of 600m/s to allow this to trigger even if GPS HAL
421 // stops output right at 600m/s, depriving this of the information of a device that reaches
422 // greater than 600m/s, and higher than the speed of sound to avoid impacting most use cases.
423 private static final float ITAR_SPEED_LIMIT_METERS_PER_SECOND = 400.0F;
424 private boolean mItarSpeedLimitExceeded = false;
426 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
428 public void registerGnssStatusCallback(IGnssStatusListener callback) {
429 mListenerHelper.addListener(callback);
433 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
434 mListenerHelper.removeListener(callback);
438 public IGnssStatusProvider getGnssStatusProvider() {
439 return mGnssStatusProvider;
442 public IGpsGeofenceHardware getGpsGeofenceProxy() {
443 return mGpsGeofenceBinder;
446 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
447 return mGnssMeasurementsProvider;
450 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
451 return mGnssNavigationMessageProvider;
455 * Callback used to listen for data connectivity changes.
457 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
458 new ConnectivityManager.NetworkCallback() {
460 public void onAvailable(Network network) {
461 if (mInjectNtpTimePending == STATE_PENDING_NETWORK) {
464 if (mDownloadXtraDataPending == STATE_PENDING_NETWORK) {
465 xtraDownloadRequest();
471 * Callback used to listen for availability of a requested SUPL connection.
472 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
473 * manage the registration/un-registration lifetimes separate.
475 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
476 new ConnectivityManager.NetworkCallback() {
478 public void onAvailable(Network network) {
479 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
483 public void onLost(Network network) {
484 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
488 public void onUnavailable() {
489 // timeout, it was not possible to establish the required connection
490 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
494 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
495 @Override public void onReceive(Context context, Intent intent) {
496 String action = intent.getAction();
497 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
498 if (action == null) {
502 if (action.equals(ALARM_WAKEUP)) {
503 startNavigating(false);
504 } else if (action.equals(ALARM_TIMEOUT)) {
506 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
507 checkSmsSuplInit(intent);
508 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
509 checkWapSuplInit(intent);
510 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
511 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
512 || Intent.ACTION_SCREEN_OFF.equals(action)
513 || Intent.ACTION_SCREEN_ON.equals(action)) {
514 updateLowPowerMode();
515 } else if (action.equals(SIM_STATE_CHANGED)) {
516 subscriptionOrSimChanged(context);
521 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
522 new OnSubscriptionsChangedListener() {
524 public void onSubscriptionsChanged() {
525 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
529 private final boolean isVerizon(String mccMnc, String imsi, String groupId) {
530 if (DEBUG) Log.d(TAG, "simOperator: " + mccMnc);
531 if (!TextUtils.isEmpty(mccMnc) || !TextUtils.isEmpty(imsi)) {
532 for (int i = 0; i < VzwMccMncList.length; i++) {
533 if ((!TextUtils.isEmpty(mccMnc) && mccMnc.equals(VzwMccMncList[i])) ||
534 (!TextUtils.isEmpty(imsi) && imsi.startsWith(VzwMccMncList[i]))) {
535 // check gid too if needed
536 if (TextUtils.isEmpty(VzwGid1List[i]) || VzwGid1List[i].equals(groupId)) {
537 if (DEBUG) Log.d(TAG, "Verizon UICC");
546 private void subscriptionOrSimChanged(Context context) {
547 if (DEBUG) Log.d(TAG, "received SIM related action: ");
548 TelephonyManager phone = (TelephonyManager)
549 mContext.getSystemService(Context.TELEPHONY_SERVICE);
550 String mccMnc = phone.getSimOperator();
551 String imsi = phone.getSubscriberId();
552 String groupId = phone.getGroupIdLevel1();
553 if (!TextUtils.isEmpty(mccMnc)) {
554 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
555 synchronized (mLock) {
556 if (isVerizon(mccMnc, imsi, groupId)) {
557 // load current properties for carrier VZW
558 loadPropertiesFromResource(context, mProperties);
559 String lpp_profile = mProperties.getProperty("LPP_PROFILE");
560 // set the persist property LPP_PROFILE for VZW
561 SystemProperties.set(LPP_PROFILE, lpp_profile);
563 // reset the persist property for Non VZW
564 SystemProperties.set(LPP_PROFILE, "");
566 reloadGpsProperties(context, mProperties);
567 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
570 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
574 private void checkSmsSuplInit(Intent intent) {
575 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
576 if (messages == null) {
577 Log.e(TAG, "Message does not exist in the intent.");
581 for (SmsMessage message : messages) {
582 if (message != null && message.mWrappedSmsMessage != null) {
583 byte[] suplInit = message.getUserData();
584 if (suplInit != null) {
585 native_agps_ni_message(suplInit, suplInit.length);
591 private void checkWapSuplInit(Intent intent) {
592 byte[] suplInit = intent.getByteArrayExtra("data");
593 if (suplInit == null) {
596 native_agps_ni_message(suplInit,suplInit.length);
599 private void updateLowPowerMode() {
600 // Disable GPS if we are in device idle mode.
601 boolean disableGps = mPowerManager.isDeviceIdleMode();
602 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
603 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
604 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
605 // If we are in battery saver mode and the screen is off, disable GPS.
606 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
609 if (disableGps != mDisableGps) {
610 mDisableGps = disableGps;
611 updateRequirements();
615 public static boolean isSupported() {
616 return native_is_supported();
619 private void reloadGpsProperties(Context context, Properties properties) {
620 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
621 loadPropertiesFromResource(context, properties);
623 boolean isPropertiesLoadedFromFile = false;
624 final String gpsHardware = SystemProperties.get("ro.hardware.gps");
626 if (!TextUtils.isEmpty(gpsHardware)) {
627 final String propFilename =
628 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
629 isPropertiesLoadedFromFile =
630 loadPropertiesFromFile(propFilename, properties);
632 if (!isPropertiesLoadedFromFile) {
633 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
635 if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
636 String lpp_prof = SystemProperties.get(LPP_PROFILE);
637 if (!TextUtils.isEmpty(lpp_prof)) {
638 // override default value of this if lpp_prof is not empty
639 properties.setProperty("LPP_PROFILE", lpp_prof);
641 // TODO: we should get rid of C2K specific setting.
642 setSuplHostPort(properties.getProperty("SUPL_HOST"),
643 properties.getProperty("SUPL_PORT"));
644 mC2KServerHost = properties.getProperty("C2K_HOST");
645 String portString = properties.getProperty("C2K_PORT");
646 if (mC2KServerHost != null && portString != null) {
648 mC2KServerPort = Integer.parseInt(portString);
649 } catch (NumberFormatException e) {
650 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
654 if (native_is_gnss_configuration_supported()) {
656 // Convert properties to string contents and send it to HAL.
657 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
658 properties.store(baos, null);
659 native_configuration_update(baos.toString());
660 if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
661 } catch (IOException ex) {
662 Log.e(TAG, "failed to dump properties contents");
665 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
669 // SUPL_ES configuration.
670 String suplESProperty = mProperties.getProperty("SUPL_ES");
671 if (suplESProperty != null) {
673 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
674 } catch (NumberFormatException e) {
675 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
680 private void loadPropertiesFromResource(Context context,
681 Properties properties) {
682 String[] configValues = context.getResources().getStringArray(
683 com.android.internal.R.array.config_gpsParameters);
684 for (String item : configValues) {
685 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
686 // We need to support "KEY =", but not "=VALUE".
687 String[] split = item.split("=");
688 if (split.length == 2) {
689 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
691 Log.w(TAG, "malformed contents: " + item);
696 private boolean loadPropertiesFromFile(String filename,
697 Properties properties) {
699 File file = new File(filename);
700 FileInputStream stream = null;
702 stream = new FileInputStream(file);
703 properties.load(stream);
705 IoUtils.closeQuietly(stream);
708 } catch (IOException e) {
709 Log.w(TAG, "Could not open GPS configuration file " + filename);
715 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
718 mNtpTime = NtpTrustedTime.getInstance(context);
719 mILocationManager = ilocationManager;
721 mLocation.setExtras(mLocationExtras);
723 // Create a wake lock
724 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
725 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
726 mWakeLock.setReferenceCounted(true);
728 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
729 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
730 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
732 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
734 // App ops service to keep track of who is accessing the GPS
735 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
736 Context.APP_OPS_SERVICE));
738 // Battery statistics service to be notified when GPS turns on or off
739 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
740 BatteryStats.SERVICE_NAME));
742 // Construct internal handler
743 mHandler = new ProviderHandler(looper);
745 // Load GPS configuration and register listeners in the background:
746 // some operations, such as opening files and registering broadcast receivers, can take a
747 // relative long time, so the ctor() is kept to create objects needed by this instance,
748 // while IO initialization and registration is delegated to our internal handler
749 // this approach is just fine because events are posted to our handler anyway
750 mProperties = new Properties();
751 // Create a GPS net-initiated handler (also needed by handleInitialize)
752 mNIHandler = new GpsNetInitiatedHandler(context,
753 mNetInitiatedListener,
755 sendMessage(INITIALIZE_HANDLER, 0, null);
757 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
759 protected boolean isAvailableInPlatform() {
760 return isSupported();
764 protected boolean isGpsEnabled() {
769 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
771 public boolean isAvailableInPlatform() {
772 return native_is_measurement_supported();
776 protected boolean registerWithService() {
777 return native_start_measurement_collection();
781 protected void unregisterFromService() {
782 native_stop_measurement_collection();
786 protected boolean isGpsEnabled() {
791 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
793 protected boolean isAvailableInPlatform() {
794 return native_is_navigation_message_supported();
798 protected boolean registerWithService() {
799 return native_start_navigation_message_collection();
803 protected void unregisterFromService() {
804 native_stop_navigation_message_collection();
808 protected boolean isGpsEnabled() {
815 * Returns the name of this provider.
818 public String getName() {
819 return LocationManager.GPS_PROVIDER;
823 public ProviderProperties getProperties() {
827 private void handleUpdateNetworkState(Network network) {
828 // retrieve NetworkInfo for this UID
829 NetworkInfo info = mConnMgr.getNetworkInfo(network);
834 boolean isConnected = info.isConnected();
836 String message = String.format(
837 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
838 agpsDataConnStateAsString(),
841 mConnMgr.getNetworkCapabilities(network));
845 if (native_is_agps_ril_supported()) {
846 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
847 boolean networkAvailable = info.isAvailable() && dataEnabled;
848 String defaultApn = getSelectedApn();
849 if (defaultApn == null) {
850 defaultApn = "dummy-apn";
853 native_update_network_state(
861 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
864 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
866 String apnName = info.getExtraInfo();
867 if (apnName == null) {
868 // assign a dummy value in the case of C2K as otherwise we will have a runtime
869 // exception in the following call to native_agps_data_conn_open
870 apnName = "dummy-apn";
872 int apnIpType = getApnIpType(apnName);
875 String message = String.format(
876 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
881 native_agps_data_conn_open(apnName, apnIpType);
882 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
884 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
889 private void handleRequestSuplConnection(InetAddress address) {
891 String message = String.format(
892 "requestSuplConnection, state=%s, address=%s",
893 agpsDataConnStateAsString(),
898 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
901 mAGpsDataConnectionIpAddr = address;
902 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
904 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
905 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
906 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
907 NetworkRequest request = requestBuilder.build();
908 mConnMgr.requestNetwork(
910 mSuplConnectivityCallback,
911 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
914 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
916 String message = String.format(
917 "releaseSuplConnection, state=%s, status=%s",
918 agpsDataConnStateAsString(),
919 agpsDataConnStatusAsString(agpsDataConnStatus));
923 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
926 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
928 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
929 switch (agpsDataConnStatus) {
930 case GPS_AGPS_DATA_CONN_FAILED:
931 native_agps_data_conn_failed();
933 case GPS_RELEASE_AGPS_DATA_CONN:
934 native_agps_data_conn_closed();
937 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
941 private void handleInjectNtpTime() {
942 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
943 // already downloading data
946 if (!isDataNetworkConnected()) {
947 // try again when network is up
948 mInjectNtpTimePending = STATE_PENDING_NETWORK;
951 mInjectNtpTimePending = STATE_DOWNLOADING;
953 // hold wake lock while task runs
955 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
956 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
961 // force refresh NTP cache when outdated
962 boolean refreshSuccess = true;
963 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
964 refreshSuccess = mNtpTime.forceRefresh();
967 // only update when NTP time is fresh
968 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
969 long time = mNtpTime.getCachedNtpTime();
970 long timeReference = mNtpTime.getCachedNtpTimeReference();
971 long certainty = mNtpTime.getCacheCertainty();
972 long now = System.currentTimeMillis();
975 Log.d(TAG, "NTP server returned: "
976 + time + " (" + new Date(time)
977 + ") reference: " + timeReference
978 + " certainty: " + certainty
979 + " system time offset: " + (time - now));
982 native_inject_time(time, timeReference, (int) certainty);
983 delay = NTP_INTERVAL;
986 Log.e(TAG, "requestTime failed");
987 delay = mNtpBackOff.nextBackoffMillis();
990 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
993 String message = String.format(
994 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
995 mOnDemandTimeInjection,
1000 if (mOnDemandTimeInjection || !refreshSuccess) {
1001 // send delayed message for next NTP injection
1002 // since this is delayed and not urgent we do not hold a wake lock here
1003 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1006 // release wake lock held by task
1007 mWakeLock.release();
1008 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1013 private void handleDownloadXtraData() {
1014 if (!mSupportsXtra) {
1015 // native code reports xtra not supported, don't try
1016 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1019 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1020 // already downloading data
1023 if (!isDataNetworkConnected()) {
1024 // try again when network is up
1025 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1028 mDownloadXtraDataPending = STATE_DOWNLOADING;
1030 // hold wake lock while task runs
1031 mWakeLock.acquire();
1032 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1033 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1036 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1037 byte[] data = xtraDownloader.downloadXtraData();
1039 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1040 native_inject_xtra_data(data, data.length);
1041 mXtraBackOff.reset();
1044 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1048 // since this is delayed and not urgent we do not hold a wake lock here
1049 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1050 mXtraBackOff.nextBackoffMillis());
1053 // release wake lock held by task
1054 mWakeLock.release();
1055 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1060 private void handleUpdateLocation(Location location) {
1061 if (location.hasAccuracy()) {
1062 native_inject_location(location.getLatitude(), location.getLongitude(),
1063 location.getAccuracy());
1068 * Enables this provider. When enabled, calls to getStatus()
1069 * must be handled. Hardware may be started up
1070 * when the provider is enabled.
1073 public void enable() {
1074 synchronized (mLock) {
1075 if (mEnabled) return;
1079 sendMessage(ENABLE, 1, null);
1082 private void setSuplHostPort(String hostString, String portString) {
1083 if (hostString != null) {
1084 mSuplServerHost = hostString;
1086 if (portString != null) {
1088 mSuplServerPort = Integer.parseInt(portString);
1089 } catch (NumberFormatException e) {
1090 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1093 if (mSuplServerHost != null
1094 && mSuplServerPort > TCP_MIN_PORT
1095 && mSuplServerPort <= TCP_MAX_PORT) {
1096 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1101 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1102 * allowed mode from properties.
1104 * @param properties GPS properties
1105 * @param agpsEnabled whether AGPS is enabled by settings value
1106 * @param singleShot whether "singleshot" is needed
1107 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1109 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1111 String modeString = properties.getProperty("SUPL_MODE");
1113 if (!TextUtils.isEmpty(modeString)) {
1115 suplMode = Integer.parseInt(modeString);
1116 } catch (NumberFormatException e) {
1117 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1118 return GPS_POSITION_MODE_STANDALONE;
1121 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1122 // such mode when it is available
1123 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1124 return GPS_POSITION_MODE_MS_BASED;
1126 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1127 // do fallback only for single-shot requests, because it is too expensive to do for
1128 // periodic requests as well
1130 && hasCapability(GPS_CAPABILITY_MSA)
1131 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1132 return GPS_POSITION_MODE_MS_ASSISTED;
1135 return GPS_POSITION_MODE_STANDALONE;
1138 private void handleEnable() {
1139 if (DEBUG) Log.d(TAG, "handleEnable");
1141 boolean enabled = native_init();
1144 mSupportsXtra = native_supports_xtra();
1146 // TODO: remove the following native calls if we can make sure they are redundant.
1147 if (mSuplServerHost != null) {
1148 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1150 if (mC2KServerHost != null) {
1151 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1154 mGnssMeasurementsProvider.onGpsEnabledChanged();
1155 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1157 synchronized (mLock) {
1160 Log.w(TAG, "Failed to enable location provider");
1165 * Disables this provider. When disabled, calls to getStatus()
1166 * need not be handled. Hardware may be shut
1167 * down while the provider is disabled.
1170 public void disable() {
1171 synchronized (mLock) {
1172 if (!mEnabled) return;
1176 sendMessage(ENABLE, 0, null);
1179 private void handleDisable() {
1180 if (DEBUG) Log.d(TAG, "handleDisable");
1182 updateClientUids(new WorkSource());
1184 mAlarmManager.cancel(mWakeupIntent);
1185 mAlarmManager.cancel(mTimeoutIntent);
1187 // do this before releasing wakelock
1190 mGnssMeasurementsProvider.onGpsEnabledChanged();
1191 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1195 public boolean isEnabled() {
1196 synchronized (mLock) {
1202 public int getStatus(Bundle extras) {
1203 if (extras != null) {
1204 extras.putInt("satellites", mSvCount);
1209 private void updateStatus(int status, int svCount) {
1210 if (status != mStatus || svCount != mSvCount) {
1213 mLocationExtras.putInt("satellites", svCount);
1214 mStatusUpdateTime = SystemClock.elapsedRealtime();
1219 public long getStatusUpdateTime() {
1220 return mStatusUpdateTime;
1224 public void setRequest(ProviderRequest request, WorkSource source) {
1225 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1228 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1229 mProviderRequest = request;
1230 mWorkSource = source;
1231 updateRequirements();
1234 // Called when the requirements for GPS may have changed
1235 private void updateRequirements() {
1236 if (mProviderRequest == null || mWorkSource == null) {
1240 boolean singleShot = false;
1242 // see if the request is for a single update
1243 if (mProviderRequest.locationRequests != null
1244 && mProviderRequest.locationRequests.size() > 0) {
1245 // if any request has zero or more than one updates
1246 // requested, then this is not single-shot mode
1249 for (LocationRequest lr : mProviderRequest.locationRequests) {
1250 if (lr.getNumUpdates() != 1) {
1256 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1257 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1258 // update client uids
1259 updateClientUids(mWorkSource);
1261 mFixInterval = (int) mProviderRequest.interval;
1263 // check for overflow
1264 if (mFixInterval != mProviderRequest.interval) {
1265 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1266 mFixInterval = Integer.MAX_VALUE;
1269 // apply request to GPS engine
1270 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1272 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1273 mFixInterval, 0, 0)) {
1274 Log.e(TAG, "set_position_mode failed in setMinTime()");
1276 } else if (!mStarted) {
1278 startNavigating(singleShot);
1281 updateClientUids(new WorkSource());
1284 mAlarmManager.cancel(mWakeupIntent);
1285 mAlarmManager.cancel(mTimeoutIntent);
1289 private void updateClientUids(WorkSource source) {
1290 // Update work source.
1291 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1292 if (changes == null) {
1295 WorkSource newWork = changes[0];
1296 WorkSource goneWork = changes[1];
1298 // Update sources that were not previously tracked.
1299 if (newWork != null) {
1301 for (int i=0; i<newWork.size(); i++) {
1303 int uid = newWork.get(i);
1304 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1305 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1306 if (uid != lastuid) {
1308 mBatteryStats.noteStartGps(uid);
1310 } catch (RemoteException e) {
1311 Log.w(TAG, "RemoteException", e);
1316 // Update sources that are no longer tracked.
1317 if (goneWork != null) {
1319 for (int i=0; i<goneWork.size(); i++) {
1321 int uid = goneWork.get(i);
1322 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1323 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1324 if (uid != lastuid) {
1326 mBatteryStats.noteStopGps(uid);
1328 } catch (RemoteException e) {
1329 Log.w(TAG, "RemoteException", e);
1336 public boolean sendExtraCommand(String command, Bundle extras) {
1338 long identity = Binder.clearCallingIdentity();
1339 boolean result = false;
1341 if ("delete_aiding_data".equals(command)) {
1342 result = deleteAidingData(extras);
1343 } else if ("force_time_injection".equals(command)) {
1346 } else if ("force_xtra_injection".equals(command)) {
1347 if (mSupportsXtra) {
1348 xtraDownloadRequest();
1352 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1355 Binder.restoreCallingIdentity(identity);
1359 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1360 public boolean isHardwareGeofenceSupported() {
1361 return native_is_geofence_supported();
1364 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1365 double longitude, double radius, int lastTransition, int monitorTransitions,
1366 int notificationResponsiveness, int unknownTimer) {
1367 return native_add_geofence(geofenceId, latitude, longitude, radius,
1368 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1371 public boolean removeHardwareGeofence(int geofenceId) {
1372 return native_remove_geofence(geofenceId);
1375 public boolean pauseHardwareGeofence(int geofenceId) {
1376 return native_pause_geofence(geofenceId);
1379 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1380 return native_resume_geofence(geofenceId, monitorTransition);
1384 private boolean deleteAidingData(Bundle extras) {
1387 if (extras == null) {
1388 flags = GPS_DELETE_ALL;
1391 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1392 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1393 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1394 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1395 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1396 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1397 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1398 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1399 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1400 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1401 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1402 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1403 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1407 native_delete_aiding_data(flags);
1414 private void startNavigating(boolean singleShot) {
1416 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1417 mTimeToFirstFix = 0;
1420 mSingleShot = singleShot;
1421 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1422 // Notify about suppressed output, if speed limit was previously exceeded.
1423 // Elsewhere, we check again with every speed output reported.
1424 if (mItarSpeedLimitExceeded) {
1425 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " +
1426 "until slow enough speed reported.");
1429 boolean agpsEnabled =
1430 (Settings.Global.getInt(mContext.getContentResolver(),
1431 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1432 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1437 switch(mPositionMode) {
1438 case GPS_POSITION_MODE_STANDALONE:
1439 mode = "standalone";
1441 case GPS_POSITION_MODE_MS_ASSISTED:
1442 mode = "MS_ASSISTED";
1444 case GPS_POSITION_MODE_MS_BASED:
1451 Log.d(TAG, "setting position_mode to " + mode);
1454 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1455 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1458 Log.e(TAG, "set_position_mode failed in startNavigating()");
1461 if (!native_start()) {
1463 Log.e(TAG, "native_start failed in startNavigating()");
1467 // reset SV count to zero
1468 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1469 mFixRequestTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1470 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1471 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1472 // and our fix interval is not short
1473 if (mFixInterval >= NO_FIX_TIMEOUT) {
1474 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1475 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1481 private void stopNavigating() {
1482 if (DEBUG) Log.d(TAG, "stopNavigating");
1485 mSingleShot = false;
1487 mTimeToFirstFix = 0;
1489 mLocationFlags = LOCATION_INVALID;
1491 // reset SV count to zero
1492 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1496 private void hibernate() {
1497 // stop GPS until our next fix interval arrives
1499 mAlarmManager.cancel(mTimeoutIntent);
1500 mAlarmManager.cancel(mWakeupIntent);
1501 long now = SystemClock.elapsedRealtime();
1502 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1505 private boolean hasCapability(int capability) {
1506 return ((mEngineCapabilities & capability) != 0);
1511 * called from native code to update our position.
1513 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1514 float speedMetersPerSecond, float bearing, float accuracy, long timestamp) {
1515 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1516 mItarSpeedLimitExceeded = speedMetersPerSecond > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1519 if (mItarSpeedLimitExceeded) {
1520 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1521 " GPS/GNSS Navigation output blocked.");
1522 return; // No output of location allowed
1525 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1526 " timestamp: " + timestamp);
1528 synchronized (mLocation) {
1529 mLocationFlags = flags;
1530 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1531 mLocation.setLatitude(latitude);
1532 mLocation.setLongitude(longitude);
1533 mLocation.setTime(timestamp);
1534 // It would be nice to push the elapsed real-time timestamp
1535 // further down the stack, but this is still useful
1536 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1538 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1539 mLocation.setAltitude(altitude);
1541 mLocation.removeAltitude();
1543 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1544 mLocation.setSpeed(speedMetersPerSecond);
1546 mLocation.removeSpeed();
1548 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1549 mLocation.setBearing(bearing);
1551 mLocation.removeBearing();
1553 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1554 mLocation.setAccuracy(accuracy);
1556 mLocation.removeAccuracy();
1558 mLocation.setExtras(mLocationExtras);
1561 mILocationManager.reportLocation(mLocation, false);
1562 } catch (RemoteException e) {
1563 Log.e(TAG, "RemoteException calling reportLocation");
1567 mLastFixTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1568 // report time to first fix
1569 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1570 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1571 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1573 // notify status listeners
1574 mListenerHelper.onFirstFix(mTimeToFirstFix);
1581 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1582 // we want to time out if we do not receive a fix
1583 // within the time out and we are requesting infrequent fixes
1584 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1585 mAlarmManager.cancel(mTimeoutIntent);
1588 // send an intent to notify that the GPS is receiving fixes.
1589 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1590 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1591 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1592 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1595 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1596 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1597 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1603 * called from native code to update our status
1605 private void reportStatus(int status) {
1606 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1608 boolean wasNavigating = mNavigating;
1610 case GPS_STATUS_SESSION_BEGIN:
1614 case GPS_STATUS_SESSION_END:
1615 mNavigating = false;
1617 case GPS_STATUS_ENGINE_ON:
1620 case GPS_STATUS_ENGINE_OFF:
1622 mNavigating = false;
1626 if (wasNavigating != mNavigating) {
1627 mListenerHelper.onStatusChanged(mNavigating);
1629 // send an intent to notify that the GPS has been enabled or disabled
1630 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1631 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1632 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1637 * called from native code to update SV info
1639 private void reportSvStatus() {
1640 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1641 mListenerHelper.onSvStatusChanged(
1649 Log.v(TAG, "SV count: " + svCount);
1651 // Calculate number of sets used in fix.
1652 int usedInFixCount = 0;
1653 for (int i = 0; i < svCount; i++) {
1654 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1658 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1659 " cn0: " + mCn0s[i]/10 +
1660 " elev: " + mSvElevations[i] +
1661 " azimuth: " + mSvAzimuths[i] +
1662 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1664 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1666 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1670 // return number of sets used in fix instead of total
1671 updateStatus(mStatus, usedInFixCount);
1673 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1674 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1675 // send an intent to notify that the GPS is no longer receiving fixes.
1676 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1677 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1678 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1679 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1684 * called from native code to update AGPS status
1686 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1688 case GPS_REQUEST_AGPS_DATA_CONN:
1689 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1690 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1691 InetAddress connectionIpAddress = null;
1692 if (ipaddr != null) {
1694 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1695 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1696 } catch (UnknownHostException e) {
1697 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1700 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1702 case GPS_RELEASE_AGPS_DATA_CONN:
1703 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1704 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1706 case GPS_AGPS_DATA_CONNECTED:
1707 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1709 case GPS_AGPS_DATA_CONN_DONE:
1710 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1712 case GPS_AGPS_DATA_CONN_FAILED:
1713 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1716 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1720 private void releaseSuplConnection(int connStatus) {
1721 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1725 * called from native code to report NMEA data received
1727 private void reportNmea(long timestamp) {
1728 if (!mItarSpeedLimitExceeded) {
1729 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1730 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1731 mListenerHelper.onNmeaReceived(timestamp, nmea);
1736 * called from native code - Gps measurements callback
1738 private void reportMeasurementData(GnssMeasurementsEvent event) {
1739 if (!mItarSpeedLimitExceeded) {
1740 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1745 * called from native code - GPS navigation message callback
1747 private void reportNavigationMessage(GnssNavigationMessage event) {
1748 if (!mItarSpeedLimitExceeded) {
1749 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1754 * called from native code to inform us what the GPS engine capabilities are
1756 private void setEngineCapabilities(int capabilities) {
1757 mEngineCapabilities = capabilities;
1759 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1760 mOnDemandTimeInjection = true;
1764 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1765 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1766 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1767 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1771 * Called from native code to inform us the hardware information.
1773 private void setGnssYearOfHardware(int yearOfHardware) {
1774 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1775 mYearOfHardware = yearOfHardware;
1778 public interface GnssSystemInfoProvider {
1780 * Returns the year of GPS hardware.
1782 int getGnssYearOfHardware();
1788 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1789 return new GnssSystemInfoProvider() {
1791 public int getGnssYearOfHardware() {
1792 return mYearOfHardware;
1798 * called from native code to request XTRA data
1800 private void xtraDownloadRequest() {
1801 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1802 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1806 * Helper method to construct a location object.
1808 private Location buildLocation(
1817 Location location = new Location(LocationManager.GPS_PROVIDER);
1818 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1819 location.setLatitude(latitude);
1820 location.setLongitude(longitude);
1821 location.setTime(timestamp);
1822 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1824 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1825 location.setAltitude(altitude);
1827 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1828 location.setSpeed(speed);
1830 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1831 location.setBearing(bearing);
1833 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1834 location.setAccuracy(accuracy);
1840 * Converts the GPS HAL status to the internal Geofence Hardware status.
1842 private int getGeofenceStatus(int status) {
1844 case GPS_GEOFENCE_OPERATION_SUCCESS:
1845 return GeofenceHardware.GEOFENCE_SUCCESS;
1846 case GPS_GEOFENCE_ERROR_GENERIC:
1847 return GeofenceHardware.GEOFENCE_FAILURE;
1848 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1849 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1850 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1851 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1852 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1853 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1854 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1855 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1862 * Called from native to report GPS Geofence transition
1863 * All geofence callbacks are called on the same thread
1865 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1866 double longitude, double altitude, float speed, float bearing, float accuracy,
1867 long timestamp, int transition, long transitionTimestamp) {
1868 if (mGeofenceHardwareImpl == null) {
1869 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1871 Location location = buildLocation(
1880 mGeofenceHardwareImpl.reportGeofenceTransition(
1884 transitionTimestamp,
1885 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1886 FusedBatchOptions.SourceTechnologies.GNSS);
1890 * called from native code to report GPS status change.
1892 private void reportGeofenceStatus(int status, int flags, double latitude,
1893 double longitude, double altitude, float speed, float bearing, float accuracy,
1895 if (mGeofenceHardwareImpl == null) {
1896 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1898 Location location = buildLocation(
1907 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1908 if(status == GPS_GEOFENCE_AVAILABLE) {
1909 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1911 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1912 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1915 FusedBatchOptions.SourceTechnologies.GNSS);
1919 * called from native code - Geofence Add callback
1921 private void reportGeofenceAddStatus(int geofenceId, int status) {
1922 if (mGeofenceHardwareImpl == null) {
1923 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1925 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1929 * called from native code - Geofence Remove callback
1931 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1932 if (mGeofenceHardwareImpl == null) {
1933 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1935 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1939 * called from native code - Geofence Pause callback
1941 private void reportGeofencePauseStatus(int geofenceId, int status) {
1942 if (mGeofenceHardwareImpl == null) {
1943 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1945 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1949 * called from native code - Geofence Resume callback
1951 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1952 if (mGeofenceHardwareImpl == null) {
1953 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1955 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1958 //=============================================================
1959 // NI Client support
1960 //=============================================================
1961 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1962 // Sends a response for an NI request to HAL.
1964 public boolean sendNiResponse(int notificationId, int userResponse)
1966 // TODO Add Permission check
1968 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1969 ", response: " + userResponse);
1970 native_send_ni_response(notificationId, userResponse);
1975 public INetInitiatedListener getNetInitiatedListener() {
1976 return mNetInitiatedListener;
1979 // Called by JNI function to report an NI request.
1980 public void reportNiNotification(
1985 int defaultResponse,
1988 int requestorIdEncoding,
1990 String extras // Encoded extra data
1993 Log.i(TAG, "reportNiNotification: entered");
1994 Log.i(TAG, "notificationId: " + notificationId +
1995 ", niType: " + niType +
1996 ", notifyFlags: " + notifyFlags +
1997 ", timeout: " + timeout +
1998 ", defaultResponse: " + defaultResponse);
2000 Log.i(TAG, "requestorId: " + requestorId +
2002 ", requestorIdEncoding: " + requestorIdEncoding +
2003 ", textEncoding: " + textEncoding);
2005 GpsNiNotification notification = new GpsNiNotification();
2007 notification.notificationId = notificationId;
2008 notification.niType = niType;
2009 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2010 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2011 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2012 notification.timeout = timeout;
2013 notification.defaultResponse = defaultResponse;
2014 notification.requestorId = requestorId;
2015 notification.text = text;
2016 notification.requestorIdEncoding = requestorIdEncoding;
2017 notification.textEncoding = textEncoding;
2019 // Process extras, assuming the format is
2020 // one of more lines of "key = value"
2021 Bundle bundle = new Bundle();
2023 if (extras == null) extras = "";
2024 Properties extraProp = new Properties();
2027 extraProp.load(new StringReader(extras));
2029 catch (IOException e)
2031 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
2034 for (Entry<Object, Object> ent : extraProp.entrySet())
2036 bundle.putString((String) ent.getKey(), (String) ent.getValue());
2039 notification.extras = bundle;
2041 mNIHandler.handleNiNotification(notification);
2045 * Called from native code to request set id info.
2046 * We should be careful about receiving null string from the TelephonyManager,
2047 * because sending null String to JNI function would cause a crash.
2050 private void requestSetID(int flags) {
2051 TelephonyManager phone = (TelephonyManager)
2052 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2053 int type = AGPS_SETID_TYPE_NONE;
2056 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2057 String data_temp = phone.getSubscriberId();
2058 if (data_temp == null) {
2059 // This means the framework does not have the SIM card ready.
2061 // This means the framework has the SIM card.
2063 type = AGPS_SETID_TYPE_IMSI;
2066 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2067 String data_temp = phone.getLine1Number();
2068 if (data_temp == null) {
2069 // This means the framework does not have the SIM card ready.
2071 // This means the framework has the SIM card.
2073 type = AGPS_SETID_TYPE_MSISDN;
2076 native_agps_set_id(type, data);
2080 * Called from native code to request utc time info
2082 private void requestUtcTime() {
2083 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2084 sendMessage(INJECT_NTP_TIME, 0, null);
2088 * Called from native code to request reference location info
2091 private void requestRefLocation(int flags) {
2092 TelephonyManager phone = (TelephonyManager)
2093 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2094 final int phoneType = phone.getPhoneType();
2095 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2096 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2097 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2098 && (phone.getNetworkOperator().length() > 3)) {
2100 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2101 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2102 int networkType = phone.getNetworkType();
2103 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2104 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2105 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2106 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2107 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2108 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2110 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2112 native_agps_set_ref_location_cellid(type, mcc, mnc,
2113 gsm_cell.getLac(), gsm_cell.getCid(), gsm_cell.getPsc());
2115 Log.e(TAG,"Error getting cell location info.");
2117 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2118 Log.e(TAG, "CDMA not supported.");
2122 private void sendMessage(int message, int arg, Object obj) {
2123 // hold a wake lock until this message is delivered
2124 // note that this assumes the message will not be removed from the queue before
2125 // it is handled (otherwise the wake lock would be leaked).
2126 mWakeLock.acquire();
2127 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2128 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2131 private final class ProviderHandler extends Handler {
2132 public ProviderHandler(Looper looper) {
2133 super(looper, null, true /*async*/);
2137 public void handleMessage(Message msg) {
2138 int message = msg.what;
2141 if (msg.arg1 == 1) {
2148 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2149 handleSetRequest(gpsRequest.request, gpsRequest.source);
2151 case UPDATE_NETWORK_STATE:
2152 handleUpdateNetworkState((Network) msg.obj);
2154 case REQUEST_SUPL_CONNECTION:
2155 handleRequestSuplConnection((InetAddress) msg.obj);
2157 case RELEASE_SUPL_CONNECTION:
2158 handleReleaseSuplConnection(msg.arg1);
2160 case INJECT_NTP_TIME:
2161 handleInjectNtpTime();
2163 case DOWNLOAD_XTRA_DATA:
2164 handleDownloadXtraData();
2166 case INJECT_NTP_TIME_FINISHED:
2167 mInjectNtpTimePending = STATE_IDLE;
2169 case DOWNLOAD_XTRA_DATA_FINISHED:
2170 mDownloadXtraDataPending = STATE_IDLE;
2172 case UPDATE_LOCATION:
2173 handleUpdateLocation((Location) msg.obj);
2175 case SUBSCRIPTION_OR_SIM_CHANGED:
2176 subscriptionOrSimChanged(mContext);
2178 case INITIALIZE_HANDLER:
2182 if (msg.arg2 == 1) {
2183 // wakelock was taken for this message, release it
2184 mWakeLock.release();
2185 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2191 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2192 * It is in charge of loading properties and registering for events that will be posted to
2195 private void handleInitialize() {
2196 // load default GPS configuration
2197 // (this configuration might change in the future based on SIM changes)
2198 reloadGpsProperties(mContext, mProperties);
2200 // TODO: When this object "finishes" we should unregister by invoking
2201 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2202 // This is not strictly necessary because it will be unregistered if the
2203 // notification fails but it is good form.
2205 // Register for SubscriptionInfo list changes which is guaranteed
2206 // to invoke onSubscriptionsChanged the first time.
2207 SubscriptionManager.from(mContext)
2208 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2210 // listen for events
2211 IntentFilter intentFilter;
2212 if (native_is_agps_ril_supported()) {
2213 intentFilter = new IntentFilter();
2214 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2215 intentFilter.addDataScheme("sms");
2216 intentFilter.addDataAuthority("localhost", "7275");
2217 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2219 intentFilter = new IntentFilter();
2220 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2222 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2223 } catch (IntentFilter.MalformedMimeTypeException e) {
2224 Log.w(TAG, "Malformed SUPL init mime type");
2226 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2228 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2229 + " HAL is not supported");
2232 intentFilter = new IntentFilter();
2233 intentFilter.addAction(ALARM_WAKEUP);
2234 intentFilter.addAction(ALARM_TIMEOUT);
2235 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2236 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2237 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2238 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2239 intentFilter.addAction(SIM_STATE_CHANGED);
2240 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2242 // register for connectivity change events, this is equivalent to the deprecated way of
2243 // registering for CONNECTIVITY_ACTION broadcasts
2244 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2245 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2246 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2247 NetworkRequest networkRequest = networkRequestBuilder.build();
2248 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2250 // listen for PASSIVE_PROVIDER updates
2251 LocationManager locManager =
2252 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2254 float minDistance = 0;
2255 boolean oneShot = false;
2256 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2257 LocationManager.PASSIVE_PROVIDER,
2261 // Don't keep track of this request since it's done on behalf of other clients
2262 // (which are kept track of separately).
2263 request.setHideFromAppOps(true);
2264 locManager.requestLocationUpdates(
2266 new NetworkLocationListener(),
2271 private final class NetworkLocationListener implements LocationListener {
2273 public void onLocationChanged(Location location) {
2274 // this callback happens on mHandler looper
2275 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2276 handleUpdateLocation(location);
2280 public void onStatusChanged(String provider, int status, Bundle extras) { }
2282 public void onProviderEnabled(String provider) { }
2284 public void onProviderDisabled(String provider) { }
2287 private String getSelectedApn() {
2288 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2289 Cursor cursor = null;
2291 cursor = mContext.getContentResolver().query(
2293 new String[] { "apn" },
2294 null /* selection */,
2295 null /* selectionArgs */,
2296 Carriers.DEFAULT_SORT_ORDER);
2297 if (cursor != null && cursor.moveToFirst()) {
2298 return cursor.getString(0);
2300 Log.e(TAG, "No APN found to select.");
2302 } catch (Exception e) {
2303 Log.e(TAG, "Error encountered on selecting the APN.", e);
2305 if (cursor != null) {
2313 private int getApnIpType(String apn) {
2314 ensureInHandlerThread();
2319 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2320 Cursor cursor = null;
2322 cursor = mContext.getContentResolver().query(
2323 Carriers.CONTENT_URI,
2324 new String[] { Carriers.PROTOCOL },
2327 Carriers.DEFAULT_SORT_ORDER);
2329 if (null != cursor && cursor.moveToFirst()) {
2330 return translateToApnIpType(cursor.getString(0), apn);
2332 Log.e(TAG, "No entry found in query for APN: " + apn);
2334 } catch (Exception e) {
2335 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2337 if (cursor != null) {
2345 private int translateToApnIpType(String ipProtocol, String apn) {
2346 if ("IP".equals(ipProtocol)) {
2349 if ("IPV6".equals(ipProtocol)) {
2352 if ("IPV4V6".equals(ipProtocol)) {
2356 // we hit the default case so the ipProtocol is not recognized
2357 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2358 Log.e(TAG, message);
2362 private void setRouting() {
2363 if (mAGpsDataConnectionIpAddr == null) {
2367 // TODO: replace the use of this deprecated API
2368 boolean result = mConnMgr.requestRouteToHostAddress(
2369 ConnectivityManager.TYPE_MOBILE_SUPL,
2370 mAGpsDataConnectionIpAddr);
2373 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2375 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2380 * @return {@code true} if there is a data network available for outgoing connections,
2381 * {@code false} otherwise.
2383 private boolean isDataNetworkConnected() {
2384 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2385 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2389 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2391 private void ensureInHandlerThread() {
2392 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2395 throw new RuntimeException("This method must run on the Handler thread.");
2399 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2401 private String agpsDataConnStateAsString() {
2402 switch(mAGpsDataConnectionState) {
2403 case AGPS_DATA_CONNECTION_CLOSED:
2405 case AGPS_DATA_CONNECTION_OPEN:
2407 case AGPS_DATA_CONNECTION_OPENING:
2415 * @return A string representing the given GPS_AGPS_DATA status.
2417 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2418 switch (agpsDataConnStatus) {
2419 case GPS_AGPS_DATA_CONNECTED:
2421 case GPS_AGPS_DATA_CONN_DONE:
2423 case GPS_AGPS_DATA_CONN_FAILED:
2425 case GPS_RELEASE_AGPS_DATA_CONN:
2427 case GPS_REQUEST_AGPS_DATA_CONN:
2435 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2436 StringBuilder s = new StringBuilder();
2437 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2438 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2439 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2441 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2442 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2443 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2444 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2445 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2446 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2447 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2448 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2451 s.append(native_get_internal_state());
2456 * A simple implementation of exponential backoff.
2458 private static final class BackOff {
2459 private static final int MULTIPLIER = 2;
2460 private final long mInitIntervalMillis;
2461 private final long mMaxIntervalMillis;
2462 private long mCurrentIntervalMillis;
2464 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2465 mInitIntervalMillis = initIntervalMillis;
2466 mMaxIntervalMillis = maxIntervalMillis;
2468 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2471 public long nextBackoffMillis() {
2472 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2473 return mMaxIntervalMillis;
2476 mCurrentIntervalMillis *= MULTIPLIER;
2477 return mCurrentIntervalMillis;
2480 public void reset() {
2481 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2485 // for GPS SV statistics
2486 private static final int MAX_SVS = 64;
2488 // preallocated arrays, to avoid memory allocation in reportStatus()
2489 private int mSvidWithFlags[] = new int[MAX_SVS];
2490 private float mCn0s[] = new float[MAX_SVS];
2491 private float mSvElevations[] = new float[MAX_SVS];
2492 private float mSvAzimuths[] = new float[MAX_SVS];
2493 private int mSvCount;
2494 // preallocated to avoid memory allocation in reportNmea()
2495 private byte[] mNmeaBuffer = new byte[120];
2497 static { class_init_native(); }
2498 private static native void class_init_native();
2499 private static native boolean native_is_supported();
2500 private static native boolean native_is_agps_ril_supported();
2501 private static native boolean native_is_gnss_configuration_supported();
2503 private native boolean native_init();
2504 private native void native_cleanup();
2505 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2506 int preferred_accuracy, int preferred_time);
2507 private native boolean native_start();
2508 private native boolean native_stop();
2509 private native void native_delete_aiding_data(int flags);
2510 // returns number of SVs
2511 // mask[0] is ephemeris mask and mask[1] is almanac mask
2512 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2514 private native int native_read_nmea(byte[] buffer, int bufferSize);
2515 private native void native_inject_location(double latitude, double longitude, float accuracy);
2518 private native void native_inject_time(long time, long timeReference, int uncertainty);
2519 private native boolean native_supports_xtra();
2520 private native void native_inject_xtra_data(byte[] data, int length);
2523 private native String native_get_internal_state();
2526 private native void native_agps_data_conn_open(String apn, int apnIpType);
2527 private native void native_agps_data_conn_closed();
2528 private native void native_agps_data_conn_failed();
2529 private native void native_agps_ni_message(byte [] msg, int length);
2530 private native void native_set_agps_server(int type, String hostname, int port);
2532 // Network-initiated (NI) Support
2533 private native void native_send_ni_response(int notificationId, int userResponse);
2536 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2537 int lac, int cid, int psc);
2538 private native void native_agps_set_id(int type, String setid);
2540 private native void native_update_network_state(boolean connected, int type,
2541 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2543 // Hardware Geofence support.
2544 private static native boolean native_is_geofence_supported();
2545 private static native boolean native_add_geofence(int geofenceId, double latitude,
2546 double longitude, double radius, int lastTransition,int monitorTransitions,
2547 int notificationResponsivenes, int unknownTimer);
2548 private static native boolean native_remove_geofence(int geofenceId);
2549 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2550 private static native boolean native_pause_geofence(int geofenceId);
2552 // Gps Hal measurements support.
2553 private static native boolean native_is_measurement_supported();
2554 private native boolean native_start_measurement_collection();
2555 private native boolean native_stop_measurement_collection();
2557 // Gps Navigation message support.
2558 private static native boolean native_is_navigation_message_supported();
2559 private native boolean native_start_navigation_message_collection();
2560 private native boolean native_stop_navigation_message_collection();
2562 // GNSS Configuration
2563 private static native void native_configuration_update(String configData);