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 sendMessage(INITIALIZE_HANDLER, 0, null);
753 // Create a GPS net-initiated handler.
754 mNIHandler = new GpsNetInitiatedHandler(context,
755 mNetInitiatedListener,
758 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
760 protected boolean isAvailableInPlatform() {
761 return isSupported();
765 protected boolean isGpsEnabled() {
770 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
772 public boolean isAvailableInPlatform() {
773 return native_is_measurement_supported();
777 protected boolean registerWithService() {
778 return native_start_measurement_collection();
782 protected void unregisterFromService() {
783 native_stop_measurement_collection();
787 protected boolean isGpsEnabled() {
792 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
794 protected boolean isAvailableInPlatform() {
795 return native_is_navigation_message_supported();
799 protected boolean registerWithService() {
800 return native_start_navigation_message_collection();
804 protected void unregisterFromService() {
805 native_stop_navigation_message_collection();
809 protected boolean isGpsEnabled() {
816 * Returns the name of this provider.
819 public String getName() {
820 return LocationManager.GPS_PROVIDER;
824 public ProviderProperties getProperties() {
828 private void handleUpdateNetworkState(Network network) {
829 // retrieve NetworkInfo for this UID
830 NetworkInfo info = mConnMgr.getNetworkInfo(network);
835 boolean isConnected = info.isConnected();
837 String message = String.format(
838 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
839 agpsDataConnStateAsString(),
842 mConnMgr.getNetworkCapabilities(network));
846 if (native_is_agps_ril_supported()) {
847 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
848 boolean networkAvailable = info.isAvailable() && dataEnabled;
849 String defaultApn = getSelectedApn();
850 if (defaultApn == null) {
851 defaultApn = "dummy-apn";
854 native_update_network_state(
862 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
865 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
867 String apnName = info.getExtraInfo();
868 if (apnName == null) {
869 // assign a dummy value in the case of C2K as otherwise we will have a runtime
870 // exception in the following call to native_agps_data_conn_open
871 apnName = "dummy-apn";
873 int apnIpType = getApnIpType(apnName);
876 String message = String.format(
877 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
882 native_agps_data_conn_open(apnName, apnIpType);
883 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
885 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
890 private void handleRequestSuplConnection(InetAddress address) {
892 String message = String.format(
893 "requestSuplConnection, state=%s, address=%s",
894 agpsDataConnStateAsString(),
899 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
902 mAGpsDataConnectionIpAddr = address;
903 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
905 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
906 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
907 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
908 NetworkRequest request = requestBuilder.build();
909 mConnMgr.requestNetwork(
911 mSuplConnectivityCallback,
912 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
915 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
917 String message = String.format(
918 "releaseSuplConnection, state=%s, status=%s",
919 agpsDataConnStateAsString(),
920 agpsDataConnStatusAsString(agpsDataConnStatus));
924 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
927 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
929 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
930 switch (agpsDataConnStatus) {
931 case GPS_AGPS_DATA_CONN_FAILED:
932 native_agps_data_conn_failed();
934 case GPS_RELEASE_AGPS_DATA_CONN:
935 native_agps_data_conn_closed();
938 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
942 private void handleInjectNtpTime() {
943 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
944 // already downloading data
947 if (!isDataNetworkConnected()) {
948 // try again when network is up
949 mInjectNtpTimePending = STATE_PENDING_NETWORK;
952 mInjectNtpTimePending = STATE_DOWNLOADING;
954 // hold wake lock while task runs
956 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
957 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
962 // force refresh NTP cache when outdated
963 boolean refreshSuccess = true;
964 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
965 refreshSuccess = mNtpTime.forceRefresh();
968 // only update when NTP time is fresh
969 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
970 long time = mNtpTime.getCachedNtpTime();
971 long timeReference = mNtpTime.getCachedNtpTimeReference();
972 long certainty = mNtpTime.getCacheCertainty();
973 long now = System.currentTimeMillis();
976 Log.d(TAG, "NTP server returned: "
977 + time + " (" + new Date(time)
978 + ") reference: " + timeReference
979 + " certainty: " + certainty
980 + " system time offset: " + (time - now));
983 native_inject_time(time, timeReference, (int) certainty);
984 delay = NTP_INTERVAL;
987 Log.e(TAG, "requestTime failed");
988 delay = mNtpBackOff.nextBackoffMillis();
991 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
994 String message = String.format(
995 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
996 mOnDemandTimeInjection,
1001 if (mOnDemandTimeInjection || !refreshSuccess) {
1002 // send delayed message for next NTP injection
1003 // since this is delayed and not urgent we do not hold a wake lock here
1004 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
1007 // release wake lock held by task
1008 mWakeLock.release();
1009 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
1014 private void handleDownloadXtraData() {
1015 if (!mSupportsXtra) {
1016 // native code reports xtra not supported, don't try
1017 Log.d(TAG, "handleDownloadXtraData() called when Xtra not supported");
1020 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
1021 // already downloading data
1024 if (!isDataNetworkConnected()) {
1025 // try again when network is up
1026 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
1029 mDownloadXtraDataPending = STATE_DOWNLOADING;
1031 // hold wake lock while task runs
1032 mWakeLock.acquire();
1033 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
1034 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
1037 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
1038 byte[] data = xtraDownloader.downloadXtraData();
1040 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
1041 native_inject_xtra_data(data, data.length);
1042 mXtraBackOff.reset();
1045 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
1049 // since this is delayed and not urgent we do not hold a wake lock here
1050 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
1051 mXtraBackOff.nextBackoffMillis());
1054 // release wake lock held by task
1055 mWakeLock.release();
1056 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1061 private void handleUpdateLocation(Location location) {
1062 if (location.hasAccuracy()) {
1063 native_inject_location(location.getLatitude(), location.getLongitude(),
1064 location.getAccuracy());
1069 * Enables this provider. When enabled, calls to getStatus()
1070 * must be handled. Hardware may be started up
1071 * when the provider is enabled.
1074 public void enable() {
1075 synchronized (mLock) {
1076 if (mEnabled) return;
1080 sendMessage(ENABLE, 1, null);
1083 private void setSuplHostPort(String hostString, String portString) {
1084 if (hostString != null) {
1085 mSuplServerHost = hostString;
1087 if (portString != null) {
1089 mSuplServerPort = Integer.parseInt(portString);
1090 } catch (NumberFormatException e) {
1091 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1094 if (mSuplServerHost != null
1095 && mSuplServerPort > TCP_MIN_PORT
1096 && mSuplServerPort <= TCP_MAX_PORT) {
1097 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1102 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1103 * allowed mode from properties.
1105 * @param properties GPS properties
1106 * @param agpsEnabled whether AGPS is enabled by settings value
1107 * @param singleShot whether "singleshot" is needed
1108 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1110 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1112 String modeString = properties.getProperty("SUPL_MODE");
1114 if (!TextUtils.isEmpty(modeString)) {
1116 suplMode = Integer.parseInt(modeString);
1117 } catch (NumberFormatException e) {
1118 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1119 return GPS_POSITION_MODE_STANDALONE;
1122 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1123 // such mode when it is available
1124 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1125 return GPS_POSITION_MODE_MS_BASED;
1127 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1128 // do fallback only for single-shot requests, because it is too expensive to do for
1129 // periodic requests as well
1131 && hasCapability(GPS_CAPABILITY_MSA)
1132 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1133 return GPS_POSITION_MODE_MS_ASSISTED;
1136 return GPS_POSITION_MODE_STANDALONE;
1139 private void handleEnable() {
1140 if (DEBUG) Log.d(TAG, "handleEnable");
1142 boolean enabled = native_init();
1145 mSupportsXtra = native_supports_xtra();
1147 // TODO: remove the following native calls if we can make sure they are redundant.
1148 if (mSuplServerHost != null) {
1149 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1151 if (mC2KServerHost != null) {
1152 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1155 mGnssMeasurementsProvider.onGpsEnabledChanged();
1156 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1158 synchronized (mLock) {
1161 Log.w(TAG, "Failed to enable location provider");
1166 * Disables this provider. When disabled, calls to getStatus()
1167 * need not be handled. Hardware may be shut
1168 * down while the provider is disabled.
1171 public void disable() {
1172 synchronized (mLock) {
1173 if (!mEnabled) return;
1177 sendMessage(ENABLE, 0, null);
1180 private void handleDisable() {
1181 if (DEBUG) Log.d(TAG, "handleDisable");
1183 updateClientUids(new WorkSource());
1185 mAlarmManager.cancel(mWakeupIntent);
1186 mAlarmManager.cancel(mTimeoutIntent);
1188 // do this before releasing wakelock
1191 mGnssMeasurementsProvider.onGpsEnabledChanged();
1192 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1196 public boolean isEnabled() {
1197 synchronized (mLock) {
1203 public int getStatus(Bundle extras) {
1204 if (extras != null) {
1205 extras.putInt("satellites", mSvCount);
1210 private void updateStatus(int status, int svCount) {
1211 if (status != mStatus || svCount != mSvCount) {
1214 mLocationExtras.putInt("satellites", svCount);
1215 mStatusUpdateTime = SystemClock.elapsedRealtime();
1220 public long getStatusUpdateTime() {
1221 return mStatusUpdateTime;
1225 public void setRequest(ProviderRequest request, WorkSource source) {
1226 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1229 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1230 mProviderRequest = request;
1231 mWorkSource = source;
1232 updateRequirements();
1235 // Called when the requirements for GPS may have changed
1236 private void updateRequirements() {
1237 if (mProviderRequest == null || mWorkSource == null) {
1241 boolean singleShot = false;
1243 // see if the request is for a single update
1244 if (mProviderRequest.locationRequests != null
1245 && mProviderRequest.locationRequests.size() > 0) {
1246 // if any request has zero or more than one updates
1247 // requested, then this is not single-shot mode
1250 for (LocationRequest lr : mProviderRequest.locationRequests) {
1251 if (lr.getNumUpdates() != 1) {
1257 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1258 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1259 // update client uids
1260 updateClientUids(mWorkSource);
1262 mFixInterval = (int) mProviderRequest.interval;
1264 // check for overflow
1265 if (mFixInterval != mProviderRequest.interval) {
1266 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1267 mFixInterval = Integer.MAX_VALUE;
1270 // apply request to GPS engine
1271 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1273 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1274 mFixInterval, 0, 0)) {
1275 Log.e(TAG, "set_position_mode failed in setMinTime()");
1277 } else if (!mStarted) {
1279 startNavigating(singleShot);
1282 updateClientUids(new WorkSource());
1285 mAlarmManager.cancel(mWakeupIntent);
1286 mAlarmManager.cancel(mTimeoutIntent);
1290 private void updateClientUids(WorkSource source) {
1291 // Update work source.
1292 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1293 if (changes == null) {
1296 WorkSource newWork = changes[0];
1297 WorkSource goneWork = changes[1];
1299 // Update sources that were not previously tracked.
1300 if (newWork != null) {
1302 for (int i=0; i<newWork.size(); i++) {
1304 int uid = newWork.get(i);
1305 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1306 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1307 if (uid != lastuid) {
1309 mBatteryStats.noteStartGps(uid);
1311 } catch (RemoteException e) {
1312 Log.w(TAG, "RemoteException", e);
1317 // Update sources that are no longer tracked.
1318 if (goneWork != null) {
1320 for (int i=0; i<goneWork.size(); i++) {
1322 int uid = goneWork.get(i);
1323 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1324 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1325 if (uid != lastuid) {
1327 mBatteryStats.noteStopGps(uid);
1329 } catch (RemoteException e) {
1330 Log.w(TAG, "RemoteException", e);
1337 public boolean sendExtraCommand(String command, Bundle extras) {
1339 long identity = Binder.clearCallingIdentity();
1340 boolean result = false;
1342 if ("delete_aiding_data".equals(command)) {
1343 result = deleteAidingData(extras);
1344 } else if ("force_time_injection".equals(command)) {
1347 } else if ("force_xtra_injection".equals(command)) {
1348 if (mSupportsXtra) {
1349 xtraDownloadRequest();
1353 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1356 Binder.restoreCallingIdentity(identity);
1360 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1361 public boolean isHardwareGeofenceSupported() {
1362 return native_is_geofence_supported();
1365 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1366 double longitude, double radius, int lastTransition, int monitorTransitions,
1367 int notificationResponsiveness, int unknownTimer) {
1368 return native_add_geofence(geofenceId, latitude, longitude, radius,
1369 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1372 public boolean removeHardwareGeofence(int geofenceId) {
1373 return native_remove_geofence(geofenceId);
1376 public boolean pauseHardwareGeofence(int geofenceId) {
1377 return native_pause_geofence(geofenceId);
1380 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1381 return native_resume_geofence(geofenceId, monitorTransition);
1385 private boolean deleteAidingData(Bundle extras) {
1388 if (extras == null) {
1389 flags = GPS_DELETE_ALL;
1392 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1393 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1394 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1395 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1396 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1397 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1398 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1399 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1400 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1401 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1402 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1403 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1404 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1408 native_delete_aiding_data(flags);
1415 private void startNavigating(boolean singleShot) {
1417 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1418 mTimeToFirstFix = 0;
1421 mSingleShot = singleShot;
1422 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1423 // Notify about suppressed output, if speed limit was previously exceeded.
1424 // Elsewhere, we check again with every speed output reported.
1425 if (mItarSpeedLimitExceeded) {
1426 Log.i(TAG, "startNavigating with ITAR limit in place. Output limited " +
1427 "until slow enough speed reported.");
1430 boolean agpsEnabled =
1431 (Settings.Global.getInt(mContext.getContentResolver(),
1432 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1433 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1438 switch(mPositionMode) {
1439 case GPS_POSITION_MODE_STANDALONE:
1440 mode = "standalone";
1442 case GPS_POSITION_MODE_MS_ASSISTED:
1443 mode = "MS_ASSISTED";
1445 case GPS_POSITION_MODE_MS_BASED:
1452 Log.d(TAG, "setting position_mode to " + mode);
1455 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1456 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1459 Log.e(TAG, "set_position_mode failed in startNavigating()");
1462 if (!native_start()) {
1464 Log.e(TAG, "native_start failed in startNavigating()");
1468 // reset SV count to zero
1469 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1470 mFixRequestTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1471 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1472 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1473 // and our fix interval is not short
1474 if (mFixInterval >= NO_FIX_TIMEOUT) {
1475 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1476 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1482 private void stopNavigating() {
1483 if (DEBUG) Log.d(TAG, "stopNavigating");
1486 mSingleShot = false;
1488 mTimeToFirstFix = 0;
1490 mLocationFlags = LOCATION_INVALID;
1492 // reset SV count to zero
1493 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1497 private void hibernate() {
1498 // stop GPS until our next fix interval arrives
1500 mAlarmManager.cancel(mTimeoutIntent);
1501 mAlarmManager.cancel(mWakeupIntent);
1502 long now = SystemClock.elapsedRealtime();
1503 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1506 private boolean hasCapability(int capability) {
1507 return ((mEngineCapabilities & capability) != 0);
1512 * called from native code to update our position.
1514 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1515 float speedMetersPerSecond, float bearing, float accuracy, long timestamp) {
1516 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1517 mItarSpeedLimitExceeded = speedMetersPerSecond > ITAR_SPEED_LIMIT_METERS_PER_SECOND;
1520 if (mItarSpeedLimitExceeded) {
1521 Log.i(TAG, "Hal reported a speed in excess of ITAR limit." +
1522 " GPS/GNSS Navigation output blocked.");
1523 return; // No output of location allowed
1526 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1527 " timestamp: " + timestamp);
1529 synchronized (mLocation) {
1530 mLocationFlags = flags;
1531 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1532 mLocation.setLatitude(latitude);
1533 mLocation.setLongitude(longitude);
1534 mLocation.setTime(timestamp);
1535 // It would be nice to push the elapsed real-time timestamp
1536 // further down the stack, but this is still useful
1537 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1539 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1540 mLocation.setAltitude(altitude);
1542 mLocation.removeAltitude();
1544 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1545 mLocation.setSpeed(speedMetersPerSecond);
1547 mLocation.removeSpeed();
1549 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1550 mLocation.setBearing(bearing);
1552 mLocation.removeBearing();
1554 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1555 mLocation.setAccuracy(accuracy);
1557 mLocation.removeAccuracy();
1559 mLocation.setExtras(mLocationExtras);
1562 mILocationManager.reportLocation(mLocation, false);
1563 } catch (RemoteException e) {
1564 Log.e(TAG, "RemoteException calling reportLocation");
1568 mLastFixTime = SystemClock.elapsedRealtime(); //return milliseconds since boot
1569 // report time to first fix
1570 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1571 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1572 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1574 // notify status listeners
1575 mListenerHelper.onFirstFix(mTimeToFirstFix);
1582 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1583 // we want to time out if we do not receive a fix
1584 // within the time out and we are requesting infrequent fixes
1585 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1586 mAlarmManager.cancel(mTimeoutIntent);
1589 // send an intent to notify that the GPS is receiving fixes.
1590 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1591 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1592 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1593 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1596 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1597 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1598 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1604 * called from native code to update our status
1606 private void reportStatus(int status) {
1607 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1609 boolean wasNavigating = mNavigating;
1611 case GPS_STATUS_SESSION_BEGIN:
1615 case GPS_STATUS_SESSION_END:
1616 mNavigating = false;
1618 case GPS_STATUS_ENGINE_ON:
1621 case GPS_STATUS_ENGINE_OFF:
1623 mNavigating = false;
1627 if (wasNavigating != mNavigating) {
1628 mListenerHelper.onStatusChanged(mNavigating);
1630 // send an intent to notify that the GPS has been enabled or disabled
1631 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1632 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1633 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1638 * called from native code to update SV info
1640 private void reportSvStatus() {
1641 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1642 mListenerHelper.onSvStatusChanged(
1650 Log.v(TAG, "SV count: " + svCount);
1652 // Calculate number of sets used in fix.
1653 int usedInFixCount = 0;
1654 for (int i = 0; i < svCount; i++) {
1655 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1659 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1660 " cn0: " + mCn0s[i]/10 +
1661 " elev: " + mSvElevations[i] +
1662 " azimuth: " + mSvAzimuths[i] +
1663 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1665 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1667 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1671 // return number of sets used in fix instead of total
1672 updateStatus(mStatus, usedInFixCount);
1674 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1675 SystemClock.elapsedRealtime() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1676 // send an intent to notify that the GPS is no longer receiving fixes.
1677 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1678 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1679 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1680 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1685 * called from native code to update AGPS status
1687 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1689 case GPS_REQUEST_AGPS_DATA_CONN:
1690 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1691 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1692 InetAddress connectionIpAddress = null;
1693 if (ipaddr != null) {
1695 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1696 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1697 } catch (UnknownHostException e) {
1698 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1701 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1703 case GPS_RELEASE_AGPS_DATA_CONN:
1704 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1705 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1707 case GPS_AGPS_DATA_CONNECTED:
1708 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1710 case GPS_AGPS_DATA_CONN_DONE:
1711 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1713 case GPS_AGPS_DATA_CONN_FAILED:
1714 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1717 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1721 private void releaseSuplConnection(int connStatus) {
1722 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1726 * called from native code to report NMEA data received
1728 private void reportNmea(long timestamp) {
1729 if (!mItarSpeedLimitExceeded) {
1730 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1731 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1732 mListenerHelper.onNmeaReceived(timestamp, nmea);
1737 * called from native code - Gps measurements callback
1739 private void reportMeasurementData(GnssMeasurementsEvent event) {
1740 if (!mItarSpeedLimitExceeded) {
1741 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1746 * called from native code - GPS navigation message callback
1748 private void reportNavigationMessage(GnssNavigationMessage event) {
1749 if (!mItarSpeedLimitExceeded) {
1750 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1755 * called from native code to inform us what the GPS engine capabilities are
1757 private void setEngineCapabilities(int capabilities) {
1758 mEngineCapabilities = capabilities;
1760 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1761 mOnDemandTimeInjection = true;
1765 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1766 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1767 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1768 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1772 * Called from native code to inform us the hardware information.
1774 private void setGnssYearOfHardware(int yearOfHardware) {
1775 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1776 mYearOfHardware = yearOfHardware;
1779 public interface GnssSystemInfoProvider {
1781 * Returns the year of GPS hardware.
1783 int getGnssYearOfHardware();
1789 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1790 return new GnssSystemInfoProvider() {
1792 public int getGnssYearOfHardware() {
1793 return mYearOfHardware;
1799 * called from native code to request XTRA data
1801 private void xtraDownloadRequest() {
1802 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1803 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1807 * Helper method to construct a location object.
1809 private Location buildLocation(
1818 Location location = new Location(LocationManager.GPS_PROVIDER);
1819 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1820 location.setLatitude(latitude);
1821 location.setLongitude(longitude);
1822 location.setTime(timestamp);
1823 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1825 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1826 location.setAltitude(altitude);
1828 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1829 location.setSpeed(speed);
1831 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1832 location.setBearing(bearing);
1834 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1835 location.setAccuracy(accuracy);
1841 * Converts the GPS HAL status to the internal Geofence Hardware status.
1843 private int getGeofenceStatus(int status) {
1845 case GPS_GEOFENCE_OPERATION_SUCCESS:
1846 return GeofenceHardware.GEOFENCE_SUCCESS;
1847 case GPS_GEOFENCE_ERROR_GENERIC:
1848 return GeofenceHardware.GEOFENCE_FAILURE;
1849 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1850 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1851 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1852 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1853 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1854 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1855 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1856 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1863 * Called from native to report GPS Geofence transition
1864 * All geofence callbacks are called on the same thread
1866 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1867 double longitude, double altitude, float speed, float bearing, float accuracy,
1868 long timestamp, int transition, long transitionTimestamp) {
1869 if (mGeofenceHardwareImpl == null) {
1870 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1872 Location location = buildLocation(
1881 mGeofenceHardwareImpl.reportGeofenceTransition(
1885 transitionTimestamp,
1886 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1887 FusedBatchOptions.SourceTechnologies.GNSS);
1891 * called from native code to report GPS status change.
1893 private void reportGeofenceStatus(int status, int flags, double latitude,
1894 double longitude, double altitude, float speed, float bearing, float accuracy,
1896 if (mGeofenceHardwareImpl == null) {
1897 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1899 Location location = buildLocation(
1908 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1909 if(status == GPS_GEOFENCE_AVAILABLE) {
1910 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1912 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1913 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1916 FusedBatchOptions.SourceTechnologies.GNSS);
1920 * called from native code - Geofence Add callback
1922 private void reportGeofenceAddStatus(int geofenceId, int status) {
1923 if (mGeofenceHardwareImpl == null) {
1924 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1926 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1930 * called from native code - Geofence Remove callback
1932 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1933 if (mGeofenceHardwareImpl == null) {
1934 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1936 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1940 * called from native code - Geofence Pause callback
1942 private void reportGeofencePauseStatus(int geofenceId, int status) {
1943 if (mGeofenceHardwareImpl == null) {
1944 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1946 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1950 * called from native code - Geofence Resume callback
1952 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1953 if (mGeofenceHardwareImpl == null) {
1954 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1956 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1959 //=============================================================
1960 // NI Client support
1961 //=============================================================
1962 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1963 // Sends a response for an NI request to HAL.
1965 public boolean sendNiResponse(int notificationId, int userResponse)
1967 // TODO Add Permission check
1969 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1970 ", response: " + userResponse);
1971 native_send_ni_response(notificationId, userResponse);
1976 public INetInitiatedListener getNetInitiatedListener() {
1977 return mNetInitiatedListener;
1980 // Called by JNI function to report an NI request.
1981 public void reportNiNotification(
1986 int defaultResponse,
1989 int requestorIdEncoding,
1991 String extras // Encoded extra data
1994 Log.i(TAG, "reportNiNotification: entered");
1995 Log.i(TAG, "notificationId: " + notificationId +
1996 ", niType: " + niType +
1997 ", notifyFlags: " + notifyFlags +
1998 ", timeout: " + timeout +
1999 ", defaultResponse: " + defaultResponse);
2001 Log.i(TAG, "requestorId: " + requestorId +
2003 ", requestorIdEncoding: " + requestorIdEncoding +
2004 ", textEncoding: " + textEncoding);
2006 GpsNiNotification notification = new GpsNiNotification();
2008 notification.notificationId = notificationId;
2009 notification.niType = niType;
2010 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
2011 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
2012 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
2013 notification.timeout = timeout;
2014 notification.defaultResponse = defaultResponse;
2015 notification.requestorId = requestorId;
2016 notification.text = text;
2017 notification.requestorIdEncoding = requestorIdEncoding;
2018 notification.textEncoding = textEncoding;
2020 // Process extras, assuming the format is
2021 // one of more lines of "key = value"
2022 Bundle bundle = new Bundle();
2024 if (extras == null) extras = "";
2025 Properties extraProp = new Properties();
2028 extraProp.load(new StringReader(extras));
2030 catch (IOException e)
2032 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
2035 for (Entry<Object, Object> ent : extraProp.entrySet())
2037 bundle.putString((String) ent.getKey(), (String) ent.getValue());
2040 notification.extras = bundle;
2042 mNIHandler.handleNiNotification(notification);
2046 * Called from native code to request set id info.
2047 * We should be careful about receiving null string from the TelephonyManager,
2048 * because sending null String to JNI function would cause a crash.
2051 private void requestSetID(int flags) {
2052 TelephonyManager phone = (TelephonyManager)
2053 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2054 int type = AGPS_SETID_TYPE_NONE;
2057 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
2058 String data_temp = phone.getSubscriberId();
2059 if (data_temp == null) {
2060 // This means the framework does not have the SIM card ready.
2062 // This means the framework has the SIM card.
2064 type = AGPS_SETID_TYPE_IMSI;
2067 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
2068 String data_temp = phone.getLine1Number();
2069 if (data_temp == null) {
2070 // This means the framework does not have the SIM card ready.
2072 // This means the framework has the SIM card.
2074 type = AGPS_SETID_TYPE_MSISDN;
2077 native_agps_set_id(type, data);
2081 * Called from native code to request utc time info
2083 private void requestUtcTime() {
2084 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2085 sendMessage(INJECT_NTP_TIME, 0, null);
2089 * Called from native code to request reference location info
2092 private void requestRefLocation(int flags) {
2093 TelephonyManager phone = (TelephonyManager)
2094 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2095 final int phoneType = phone.getPhoneType();
2096 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2097 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2098 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2099 && (phone.getNetworkOperator().length() > 3)) {
2101 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2102 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2103 int networkType = phone.getNetworkType();
2104 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2105 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2106 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2107 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2108 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2109 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2111 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2113 native_agps_set_ref_location_cellid(type, mcc, mnc,
2114 gsm_cell.getLac(), gsm_cell.getCid(), gsm_cell.getPsc());
2116 Log.e(TAG,"Error getting cell location info.");
2118 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2119 Log.e(TAG, "CDMA not supported.");
2123 private void sendMessage(int message, int arg, Object obj) {
2124 // hold a wake lock until this message is delivered
2125 // note that this assumes the message will not be removed from the queue before
2126 // it is handled (otherwise the wake lock would be leaked).
2127 mWakeLock.acquire();
2128 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2129 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2132 private final class ProviderHandler extends Handler {
2133 public ProviderHandler(Looper looper) {
2134 super(looper, null, true /*async*/);
2138 public void handleMessage(Message msg) {
2139 int message = msg.what;
2142 if (msg.arg1 == 1) {
2149 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2150 handleSetRequest(gpsRequest.request, gpsRequest.source);
2152 case UPDATE_NETWORK_STATE:
2153 handleUpdateNetworkState((Network) msg.obj);
2155 case REQUEST_SUPL_CONNECTION:
2156 handleRequestSuplConnection((InetAddress) msg.obj);
2158 case RELEASE_SUPL_CONNECTION:
2159 handleReleaseSuplConnection(msg.arg1);
2161 case INJECT_NTP_TIME:
2162 handleInjectNtpTime();
2164 case DOWNLOAD_XTRA_DATA:
2165 handleDownloadXtraData();
2167 case INJECT_NTP_TIME_FINISHED:
2168 mInjectNtpTimePending = STATE_IDLE;
2170 case DOWNLOAD_XTRA_DATA_FINISHED:
2171 mDownloadXtraDataPending = STATE_IDLE;
2173 case UPDATE_LOCATION:
2174 handleUpdateLocation((Location) msg.obj);
2176 case SUBSCRIPTION_OR_SIM_CHANGED:
2177 subscriptionOrSimChanged(mContext);
2179 case INITIALIZE_HANDLER:
2183 if (msg.arg2 == 1) {
2184 // wakelock was taken for this message, release it
2185 mWakeLock.release();
2186 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2192 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2193 * It is in charge of loading properties and registering for events that will be posted to
2196 private void handleInitialize() {
2197 // load default GPS configuration
2198 // (this configuration might change in the future based on SIM changes)
2199 reloadGpsProperties(mContext, mProperties);
2201 // TODO: When this object "finishes" we should unregister by invoking
2202 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2203 // This is not strictly necessary because it will be unregistered if the
2204 // notification fails but it is good form.
2206 // Register for SubscriptionInfo list changes which is guaranteed
2207 // to invoke onSubscriptionsChanged the first time.
2208 SubscriptionManager.from(mContext)
2209 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2211 // listen for events
2212 IntentFilter intentFilter;
2213 if (native_is_agps_ril_supported()) {
2214 intentFilter = new IntentFilter();
2215 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2216 intentFilter.addDataScheme("sms");
2217 intentFilter.addDataAuthority("localhost", "7275");
2218 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2220 intentFilter = new IntentFilter();
2221 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2223 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2224 } catch (IntentFilter.MalformedMimeTypeException e) {
2225 Log.w(TAG, "Malformed SUPL init mime type");
2227 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2229 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2230 + " HAL is not supported");
2233 intentFilter = new IntentFilter();
2234 intentFilter.addAction(ALARM_WAKEUP);
2235 intentFilter.addAction(ALARM_TIMEOUT);
2236 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2237 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2238 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2239 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2240 intentFilter.addAction(SIM_STATE_CHANGED);
2241 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2243 // register for connectivity change events, this is equivalent to the deprecated way of
2244 // registering for CONNECTIVITY_ACTION broadcasts
2245 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2246 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2247 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2248 NetworkRequest networkRequest = networkRequestBuilder.build();
2249 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2251 // listen for PASSIVE_PROVIDER updates
2252 LocationManager locManager =
2253 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2255 float minDistance = 0;
2256 boolean oneShot = false;
2257 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2258 LocationManager.PASSIVE_PROVIDER,
2262 // Don't keep track of this request since it's done on behalf of other clients
2263 // (which are kept track of separately).
2264 request.setHideFromAppOps(true);
2265 locManager.requestLocationUpdates(
2267 new NetworkLocationListener(),
2272 private final class NetworkLocationListener implements LocationListener {
2274 public void onLocationChanged(Location location) {
2275 // this callback happens on mHandler looper
2276 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2277 handleUpdateLocation(location);
2281 public void onStatusChanged(String provider, int status, Bundle extras) { }
2283 public void onProviderEnabled(String provider) { }
2285 public void onProviderDisabled(String provider) { }
2288 private String getSelectedApn() {
2289 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2290 Cursor cursor = null;
2292 cursor = mContext.getContentResolver().query(
2294 new String[] { "apn" },
2295 null /* selection */,
2296 null /* selectionArgs */,
2297 Carriers.DEFAULT_SORT_ORDER);
2298 if (cursor != null && cursor.moveToFirst()) {
2299 return cursor.getString(0);
2301 Log.e(TAG, "No APN found to select.");
2303 } catch (Exception e) {
2304 Log.e(TAG, "Error encountered on selecting the APN.", e);
2306 if (cursor != null) {
2314 private int getApnIpType(String apn) {
2315 ensureInHandlerThread();
2320 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2321 Cursor cursor = null;
2323 cursor = mContext.getContentResolver().query(
2324 Carriers.CONTENT_URI,
2325 new String[] { Carriers.PROTOCOL },
2328 Carriers.DEFAULT_SORT_ORDER);
2330 if (null != cursor && cursor.moveToFirst()) {
2331 return translateToApnIpType(cursor.getString(0), apn);
2333 Log.e(TAG, "No entry found in query for APN: " + apn);
2335 } catch (Exception e) {
2336 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2338 if (cursor != null) {
2346 private int translateToApnIpType(String ipProtocol, String apn) {
2347 if ("IP".equals(ipProtocol)) {
2350 if ("IPV6".equals(ipProtocol)) {
2353 if ("IPV4V6".equals(ipProtocol)) {
2357 // we hit the default case so the ipProtocol is not recognized
2358 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2359 Log.e(TAG, message);
2363 private void setRouting() {
2364 if (mAGpsDataConnectionIpAddr == null) {
2368 // TODO: replace the use of this deprecated API
2369 boolean result = mConnMgr.requestRouteToHostAddress(
2370 ConnectivityManager.TYPE_MOBILE_SUPL,
2371 mAGpsDataConnectionIpAddr);
2374 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2376 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2381 * @return {@code true} if there is a data network available for outgoing connections,
2382 * {@code false} otherwise.
2384 private boolean isDataNetworkConnected() {
2385 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2386 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2390 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2392 private void ensureInHandlerThread() {
2393 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2396 throw new RuntimeException("This method must run on the Handler thread.");
2400 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2402 private String agpsDataConnStateAsString() {
2403 switch(mAGpsDataConnectionState) {
2404 case AGPS_DATA_CONNECTION_CLOSED:
2406 case AGPS_DATA_CONNECTION_OPEN:
2408 case AGPS_DATA_CONNECTION_OPENING:
2416 * @return A string representing the given GPS_AGPS_DATA status.
2418 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2419 switch (agpsDataConnStatus) {
2420 case GPS_AGPS_DATA_CONNECTED:
2422 case GPS_AGPS_DATA_CONN_DONE:
2424 case GPS_AGPS_DATA_CONN_FAILED:
2426 case GPS_RELEASE_AGPS_DATA_CONN:
2428 case GPS_REQUEST_AGPS_DATA_CONN:
2436 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2437 StringBuilder s = new StringBuilder();
2438 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2439 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2440 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2442 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2443 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2444 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2445 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2446 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2447 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2448 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2449 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2452 s.append(native_get_internal_state());
2457 * A simple implementation of exponential backoff.
2459 private static final class BackOff {
2460 private static final int MULTIPLIER = 2;
2461 private final long mInitIntervalMillis;
2462 private final long mMaxIntervalMillis;
2463 private long mCurrentIntervalMillis;
2465 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2466 mInitIntervalMillis = initIntervalMillis;
2467 mMaxIntervalMillis = maxIntervalMillis;
2469 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2472 public long nextBackoffMillis() {
2473 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2474 return mMaxIntervalMillis;
2477 mCurrentIntervalMillis *= MULTIPLIER;
2478 return mCurrentIntervalMillis;
2481 public void reset() {
2482 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2486 // for GPS SV statistics
2487 private static final int MAX_SVS = 64;
2489 // preallocated arrays, to avoid memory allocation in reportStatus()
2490 private int mSvidWithFlags[] = new int[MAX_SVS];
2491 private float mCn0s[] = new float[MAX_SVS];
2492 private float mSvElevations[] = new float[MAX_SVS];
2493 private float mSvAzimuths[] = new float[MAX_SVS];
2494 private int mSvCount;
2495 // preallocated to avoid memory allocation in reportNmea()
2496 private byte[] mNmeaBuffer = new byte[120];
2498 static { class_init_native(); }
2499 private static native void class_init_native();
2500 private static native boolean native_is_supported();
2501 private static native boolean native_is_agps_ril_supported();
2502 private static native boolean native_is_gnss_configuration_supported();
2504 private native boolean native_init();
2505 private native void native_cleanup();
2506 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2507 int preferred_accuracy, int preferred_time);
2508 private native boolean native_start();
2509 private native boolean native_stop();
2510 private native void native_delete_aiding_data(int flags);
2511 // returns number of SVs
2512 // mask[0] is ephemeris mask and mask[1] is almanac mask
2513 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2515 private native int native_read_nmea(byte[] buffer, int bufferSize);
2516 private native void native_inject_location(double latitude, double longitude, float accuracy);
2519 private native void native_inject_time(long time, long timeReference, int uncertainty);
2520 private native boolean native_supports_xtra();
2521 private native void native_inject_xtra_data(byte[] data, int length);
2524 private native String native_get_internal_state();
2527 private native void native_agps_data_conn_open(String apn, int apnIpType);
2528 private native void native_agps_data_conn_closed();
2529 private native void native_agps_data_conn_failed();
2530 private native void native_agps_ni_message(byte [] msg, int length);
2531 private native void native_set_agps_server(int type, String hostname, int port);
2533 // Network-initiated (NI) Support
2534 private native void native_send_ni_response(int notificationId, int userResponse);
2537 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2538 int lac, int cid, int psc);
2539 private native void native_agps_set_id(int type, String setid);
2541 private native void native_update_network_state(boolean connected, int type,
2542 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2544 // Hardware Geofence support.
2545 private static native boolean native_is_geofence_supported();
2546 private static native boolean native_add_geofence(int geofenceId, double latitude,
2547 double longitude, double radius, int lastTransition,int monitorTransitions,
2548 int notificationResponsivenes, int unknownTimer);
2549 private static native boolean native_remove_geofence(int geofenceId);
2550 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2551 private static native boolean native_pause_geofence(int geofenceId);
2553 // Gps Hal measurements support.
2554 private static native boolean native_is_measurement_supported();
2555 private native boolean native_start_measurement_collection();
2556 private native boolean native_stop_measurement_collection();
2558 // Gps Navigation message support.
2559 private static native boolean native_is_navigation_message_supported();
2560 private native boolean native_start_navigation_message_collection();
2561 private native boolean native_stop_navigation_message_collection();
2563 // GNSS Configuration
2564 private static native void native_configuration_update(String configData);