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 private final PowerManager mPowerManager;
397 private final AlarmManager mAlarmManager;
398 private final PendingIntent mWakeupIntent;
399 private final PendingIntent mTimeoutIntent;
401 private final IAppOpsService mAppOpsService;
402 private final IBatteryStats mBatteryStats;
404 // only modified on handler thread
405 private WorkSource mClientSource = new WorkSource();
407 private GeofenceHardwareImpl mGeofenceHardwareImpl;
409 private int mYearOfHardware = 0;
411 private final IGnssStatusProvider mGnssStatusProvider = new IGnssStatusProvider.Stub() {
413 public void registerGnssStatusCallback(IGnssStatusListener callback) {
414 mListenerHelper.addListener(callback);
418 public void unregisterGnssStatusCallback(IGnssStatusListener callback) {
419 mListenerHelper.removeListener(callback);
423 public IGnssStatusProvider getGnssStatusProvider() {
424 return mGnssStatusProvider;
427 public IGpsGeofenceHardware getGpsGeofenceProxy() {
428 return mGpsGeofenceBinder;
431 public GnssMeasurementsProvider getGnssMeasurementsProvider() {
432 return mGnssMeasurementsProvider;
435 public GnssNavigationMessageProvider getGnssNavigationMessageProvider() {
436 return mGnssNavigationMessageProvider;
440 * Callback used to listen for data connectivity changes.
442 private final ConnectivityManager.NetworkCallback mNetworkConnectivityCallback =
443 new ConnectivityManager.NetworkCallback() {
445 public void onAvailable(Network network) {
447 xtraDownloadRequest();
452 * Callback used to listen for availability of a requested SUPL connection.
453 * It is kept as a separate instance from {@link #mNetworkConnectivityCallback} to be able to
454 * manage the registration/un-registration lifetimes separate.
456 private final ConnectivityManager.NetworkCallback mSuplConnectivityCallback =
457 new ConnectivityManager.NetworkCallback() {
459 public void onAvailable(Network network) {
460 sendMessage(UPDATE_NETWORK_STATE, 0 /*arg*/, network);
464 public void onLost(Network network) {
465 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
469 public void onUnavailable() {
470 // timeout, it was not possible to establish the required connection
471 releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
475 private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
476 @Override public void onReceive(Context context, Intent intent) {
477 String action = intent.getAction();
478 if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
479 if (action == null) {
483 if (action.equals(ALARM_WAKEUP)) {
484 startNavigating(false);
485 } else if (action.equals(ALARM_TIMEOUT)) {
487 } else if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
488 checkSmsSuplInit(intent);
489 } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
490 checkWapSuplInit(intent);
491 } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)
492 || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)
493 || Intent.ACTION_SCREEN_OFF.equals(action)
494 || Intent.ACTION_SCREEN_ON.equals(action)) {
495 updateLowPowerMode();
496 } else if (action.equals(SIM_STATE_CHANGED)) {
497 subscriptionOrSimChanged(context);
502 private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
503 new OnSubscriptionsChangedListener() {
505 public void onSubscriptionsChanged() {
506 sendMessage(SUBSCRIPTION_OR_SIM_CHANGED, 0, null);
510 private void subscriptionOrSimChanged(Context context) {
511 if (DEBUG) Log.d(TAG, "received SIM related action: ");
512 TelephonyManager phone = (TelephonyManager)
513 mContext.getSystemService(Context.TELEPHONY_SERVICE);
514 String mccMnc = phone.getSimOperator();
515 if (!TextUtils.isEmpty(mccMnc)) {
516 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is available: " + mccMnc);
517 synchronized (mLock) {
518 reloadGpsProperties(context, mProperties);
519 mNIHandler.setSuplEsEnabled(mSuplEsEnabled);
522 if (DEBUG) Log.d(TAG, "SIM MCC/MNC is still not available");
526 private void checkSmsSuplInit(Intent intent) {
527 SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
528 if (messages == null) {
529 Log.e(TAG, "Message does not exist in the intent.");
533 for (SmsMessage message : messages) {
534 if (message != null && message.mWrappedSmsMessage != null) {
535 byte[] suplInit = message.getUserData();
536 if (suplInit != null) {
537 native_agps_ni_message(suplInit, suplInit.length);
543 private void checkWapSuplInit(Intent intent) {
544 byte[] suplInit = intent.getByteArrayExtra("data");
545 if (suplInit == null) {
548 native_agps_ni_message(suplInit,suplInit.length);
551 private void updateLowPowerMode() {
552 // Disable GPS if we are in device idle mode.
553 boolean disableGps = mPowerManager.isDeviceIdleMode();
554 switch (Settings.Secure.getInt(mContext.getContentResolver(), BATTERY_SAVER_GPS_MODE,
555 BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF)) {
556 case BATTERY_SAVER_MODE_DISABLED_WHEN_SCREEN_OFF:
557 // If we are in battery saver mode and the screen is off, disable GPS.
558 disableGps |= mPowerManager.isPowerSaveMode() && !mPowerManager.isInteractive();
561 if (disableGps != mDisableGps) {
562 mDisableGps = disableGps;
563 updateRequirements();
567 public static boolean isSupported() {
568 return native_is_supported();
571 private void reloadGpsProperties(Context context, Properties properties) {
572 if (DEBUG) Log.d(TAG, "Reset GPS properties, previous size = " + properties.size());
573 loadPropertiesFromResource(context, properties);
574 boolean isPropertiesLoadedFromFile = false;
575 final String gpsHardware = SystemProperties.get("ro.hardware.gps");
576 if (!TextUtils.isEmpty(gpsHardware)) {
577 final String propFilename =
578 PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
579 isPropertiesLoadedFromFile =
580 loadPropertiesFromFile(propFilename, properties);
582 if (!isPropertiesLoadedFromFile) {
583 loadPropertiesFromFile(DEFAULT_PROPERTIES_FILE, properties);
585 if (DEBUG) Log.d(TAG, "GPS properties reloaded, size = " + properties.size());
587 // TODO: we should get rid of C2K specific setting.
588 setSuplHostPort(properties.getProperty("SUPL_HOST"),
589 properties.getProperty("SUPL_PORT"));
590 mC2KServerHost = properties.getProperty("C2K_HOST");
591 String portString = properties.getProperty("C2K_PORT");
592 if (mC2KServerHost != null && portString != null) {
594 mC2KServerPort = Integer.parseInt(portString);
595 } catch (NumberFormatException e) {
596 Log.e(TAG, "unable to parse C2K_PORT: " + portString);
600 if (native_is_gnss_configuration_supported()) {
602 // Convert properties to string contents and send it to HAL.
603 ByteArrayOutputStream baos = new ByteArrayOutputStream(4096);
604 properties.store(baos, null);
605 native_configuration_update(baos.toString());
606 if (DEBUG) Log.d(TAG, "final config = " + baos.toString());
607 } catch (IOException ex) {
608 Log.e(TAG, "failed to dump properties contents");
611 Log.d(TAG, "Skipped configuration update because GNSS configuration in GPS HAL is not"
615 // SUPL_ES configuration.
616 String suplESProperty = mProperties.getProperty("SUPL_ES");
617 if (suplESProperty != null) {
619 mSuplEsEnabled = (Integer.parseInt(suplESProperty) == 1);
620 } catch (NumberFormatException e) {
621 Log.e(TAG, "unable to parse SUPL_ES: " + suplESProperty);
626 private void loadPropertiesFromResource(Context context,
627 Properties properties) {
628 String[] configValues = context.getResources().getStringArray(
629 com.android.internal.R.array.config_gpsParameters);
630 for (String item : configValues) {
631 if (DEBUG) Log.d(TAG, "GpsParamsResource: " + item);
632 // We need to support "KEY =", but not "=VALUE".
633 String[] split = item.split("=");
634 if (split.length == 2) {
635 properties.setProperty(split[0].trim().toUpperCase(), split[1]);
637 Log.w(TAG, "malformed contents: " + item);
642 private boolean loadPropertiesFromFile(String filename,
643 Properties properties) {
645 File file = new File(filename);
646 FileInputStream stream = null;
648 stream = new FileInputStream(file);
649 properties.load(stream);
651 IoUtils.closeQuietly(stream);
654 } catch (IOException e) {
655 Log.w(TAG, "Could not open GPS configuration file " + filename);
661 public GnssLocationProvider(Context context, ILocationManager ilocationManager,
664 mNtpTime = NtpTrustedTime.getInstance(context);
665 mILocationManager = ilocationManager;
667 mLocation.setExtras(mLocationExtras);
669 // Create a wake lock
670 mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
671 mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_KEY);
672 mWakeLock.setReferenceCounted(true);
674 mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
675 mWakeupIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_WAKEUP), 0);
676 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, new Intent(ALARM_TIMEOUT), 0);
678 mConnMgr = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
680 // App ops service to keep track of who is accessing the GPS
681 mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService(
682 Context.APP_OPS_SERVICE));
684 // Battery statistics service to be notified when GPS turns on or off
685 mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
686 BatteryStats.SERVICE_NAME));
688 // Construct internal handler
689 mHandler = new ProviderHandler(looper);
691 // Load GPS configuration and register listeners in the background:
692 // some operations, such as opening files and registering broadcast receivers, can take a
693 // relative long time, so the ctor() is kept to create objects needed by this instance,
694 // while IO initialization and registration is delegated to our internal handler
695 // this approach is just fine because events are posted to our handler anyway
696 mProperties = new Properties();
697 sendMessage(INITIALIZE_HANDLER, 0, null);
699 // Create a GPS net-initiated handler.
700 mNIHandler = new GpsNetInitiatedHandler(context,
701 mNetInitiatedListener,
704 mListenerHelper = new GnssStatusListenerHelper(mHandler) {
706 protected boolean isAvailableInPlatform() {
707 return isSupported();
711 protected boolean isGpsEnabled() {
716 mGnssMeasurementsProvider = new GnssMeasurementsProvider(mHandler) {
718 public boolean isAvailableInPlatform() {
719 return native_is_measurement_supported();
723 protected boolean registerWithService() {
724 return native_start_measurement_collection();
728 protected void unregisterFromService() {
729 native_stop_measurement_collection();
733 protected boolean isGpsEnabled() {
738 mGnssNavigationMessageProvider = new GnssNavigationMessageProvider(mHandler) {
740 protected boolean isAvailableInPlatform() {
741 return native_is_navigation_message_supported();
745 protected boolean registerWithService() {
746 return native_start_navigation_message_collection();
750 protected void unregisterFromService() {
751 native_stop_navigation_message_collection();
755 protected boolean isGpsEnabled() {
762 * Returns the name of this provider.
765 public String getName() {
766 return LocationManager.GPS_PROVIDER;
770 public ProviderProperties getProperties() {
774 private void handleUpdateNetworkState(Network network) {
775 // retrieve NetworkInfo for this UID
776 NetworkInfo info = mConnMgr.getNetworkInfo(network);
781 boolean isConnected = info.isConnected();
783 String message = String.format(
784 "UpdateNetworkState, state=%s, connected=%s, info=%s, capabilities=%S",
785 agpsDataConnStateAsString(),
788 mConnMgr.getNetworkCapabilities(network));
792 if (native_is_agps_ril_supported()) {
793 boolean dataEnabled = TelephonyManager.getDefault().getDataEnabled();
794 boolean networkAvailable = info.isAvailable() && dataEnabled;
795 String defaultApn = getSelectedApn();
796 if (defaultApn == null) {
797 defaultApn = "dummy-apn";
800 native_update_network_state(
808 Log.d(TAG, "Skipped network state update because GPS HAL AGPS-RIL is not supported");
811 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_OPENING) {
813 String apnName = info.getExtraInfo();
814 if (apnName == null) {
815 // assign a dummy value in the case of C2K as otherwise we will have a runtime
816 // exception in the following call to native_agps_data_conn_open
817 apnName = "dummy-apn";
819 int apnIpType = getApnIpType(apnName);
822 String message = String.format(
823 "native_agps_data_conn_open: mAgpsApn=%s, mApnIpType=%s",
828 native_agps_data_conn_open(apnName, apnIpType);
829 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPEN;
831 handleReleaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
836 private void handleRequestSuplConnection(InetAddress address) {
838 String message = String.format(
839 "requestSuplConnection, state=%s, address=%s",
840 agpsDataConnStateAsString(),
845 if (mAGpsDataConnectionState != AGPS_DATA_CONNECTION_CLOSED) {
848 mAGpsDataConnectionIpAddr = address;
849 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
851 NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
852 requestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
853 requestBuilder.addCapability(NetworkCapabilities.NET_CAPABILITY_SUPL);
854 NetworkRequest request = requestBuilder.build();
855 mConnMgr.requestNetwork(
857 mSuplConnectivityCallback,
858 ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
861 private void handleReleaseSuplConnection(int agpsDataConnStatus) {
863 String message = String.format(
864 "releaseSuplConnection, state=%s, status=%s",
865 agpsDataConnStateAsString(),
866 agpsDataConnStatusAsString(agpsDataConnStatus));
870 if (mAGpsDataConnectionState == AGPS_DATA_CONNECTION_CLOSED) {
873 mAGpsDataConnectionState = AGPS_DATA_CONNECTION_CLOSED;
875 mConnMgr.unregisterNetworkCallback(mSuplConnectivityCallback);
876 switch (agpsDataConnStatus) {
877 case GPS_AGPS_DATA_CONN_FAILED:
878 native_agps_data_conn_failed();
880 case GPS_RELEASE_AGPS_DATA_CONN:
881 native_agps_data_conn_closed();
884 Log.e(TAG, "Invalid status to release SUPL connection: " + agpsDataConnStatus);
888 private void handleInjectNtpTime() {
889 if (mInjectNtpTimePending == STATE_DOWNLOADING) {
890 // already downloading data
893 if (!isDataNetworkConnected()) {
894 // try again when network is up
895 mInjectNtpTimePending = STATE_PENDING_NETWORK;
898 mInjectNtpTimePending = STATE_DOWNLOADING;
900 // hold wake lock while task runs
902 Log.i(TAG, "WakeLock acquired by handleInjectNtpTime()");
903 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
908 // force refresh NTP cache when outdated
909 boolean refreshSuccess = true;
910 if (mNtpTime.getCacheAge() >= NTP_INTERVAL) {
911 refreshSuccess = mNtpTime.forceRefresh();
914 // only update when NTP time is fresh
915 if (mNtpTime.getCacheAge() < NTP_INTERVAL) {
916 long time = mNtpTime.getCachedNtpTime();
917 long timeReference = mNtpTime.getCachedNtpTimeReference();
918 long certainty = mNtpTime.getCacheCertainty();
919 long now = System.currentTimeMillis();
922 Log.d(TAG, "NTP server returned: "
923 + time + " (" + new Date(time)
924 + ") reference: " + timeReference
925 + " certainty: " + certainty
926 + " system time offset: " + (time - now));
929 native_inject_time(time, timeReference, (int) certainty);
930 delay = NTP_INTERVAL;
933 Log.e(TAG, "requestTime failed");
934 delay = mNtpBackOff.nextBackoffMillis();
937 sendMessage(INJECT_NTP_TIME_FINISHED, 0, null);
940 String message = String.format(
941 "onDemandTimeInjection=%s, refreshSuccess=%s, delay=%s",
942 mOnDemandTimeInjection,
947 if (mOnDemandTimeInjection || !refreshSuccess) {
948 // send delayed message for next NTP injection
949 // since this is delayed and not urgent we do not hold a wake lock here
950 mHandler.sendEmptyMessageDelayed(INJECT_NTP_TIME, delay);
953 // release wake lock held by task
955 Log.i(TAG, "WakeLock released by handleInjectNtpTime()");
960 private void handleDownloadXtraData() {
961 if (mDownloadXtraDataPending == STATE_DOWNLOADING) {
962 // already downloading data
965 if (!isDataNetworkConnected()) {
966 // try again when network is up
967 mDownloadXtraDataPending = STATE_PENDING_NETWORK;
970 mDownloadXtraDataPending = STATE_DOWNLOADING;
972 // hold wake lock while task runs
974 Log.i(TAG, "WakeLock acquired by handleDownloadXtraData()");
975 AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() {
978 GpsXtraDownloader xtraDownloader = new GpsXtraDownloader(mProperties);
979 byte[] data = xtraDownloader.downloadXtraData();
981 if (DEBUG) Log.d(TAG, "calling native_inject_xtra_data");
982 native_inject_xtra_data(data, data.length);
983 mXtraBackOff.reset();
986 sendMessage(DOWNLOAD_XTRA_DATA_FINISHED, 0, null);
990 // since this is delayed and not urgent we do not hold a wake lock here
991 mHandler.sendEmptyMessageDelayed(DOWNLOAD_XTRA_DATA,
992 mXtraBackOff.nextBackoffMillis());
995 // release wake lock held by task
997 Log.i(TAG, "WakeLock released by handleDownloadXtraData()");
1002 private void handleUpdateLocation(Location location) {
1003 if (location.hasAccuracy()) {
1004 native_inject_location(location.getLatitude(), location.getLongitude(),
1005 location.getAccuracy());
1010 * Enables this provider. When enabled, calls to getStatus()
1011 * must be handled. Hardware may be started up
1012 * when the provider is enabled.
1015 public void enable() {
1016 synchronized (mLock) {
1017 if (mEnabled) return;
1021 sendMessage(ENABLE, 1, null);
1024 private void setSuplHostPort(String hostString, String portString) {
1025 if (hostString != null) {
1026 mSuplServerHost = hostString;
1028 if (portString != null) {
1030 mSuplServerPort = Integer.parseInt(portString);
1031 } catch (NumberFormatException e) {
1032 Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
1035 if (mSuplServerHost != null
1036 && mSuplServerPort > TCP_MIN_PORT
1037 && mSuplServerPort <= TCP_MAX_PORT) {
1038 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1043 * Checks what SUPL mode to use, according to the AGPS mode as well as the
1044 * allowed mode from properties.
1046 * @param properties GPS properties
1047 * @param agpsEnabled whether AGPS is enabled by settings value
1048 * @param singleShot whether "singleshot" is needed
1049 * @return SUPL mode (MSA vs MSB vs STANDALONE)
1051 private int getSuplMode(Properties properties, boolean agpsEnabled, boolean singleShot) {
1053 String modeString = properties.getProperty("SUPL_MODE");
1055 if (!TextUtils.isEmpty(modeString)) {
1057 suplMode = Integer.parseInt(modeString);
1058 } catch (NumberFormatException e) {
1059 Log.e(TAG, "unable to parse SUPL_MODE: " + modeString);
1060 return GPS_POSITION_MODE_STANDALONE;
1063 // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
1064 // such mode when it is available
1065 if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
1066 return GPS_POSITION_MODE_MS_BASED;
1068 // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
1069 // do fallback only for single-shot requests, because it is too expensive to do for
1070 // periodic requests as well
1072 && hasCapability(GPS_CAPABILITY_MSA)
1073 && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
1074 return GPS_POSITION_MODE_MS_ASSISTED;
1077 return GPS_POSITION_MODE_STANDALONE;
1080 private void handleEnable() {
1081 if (DEBUG) Log.d(TAG, "handleEnable");
1083 boolean enabled = native_init();
1086 mSupportsXtra = native_supports_xtra();
1088 // TODO: remove the following native calls if we can make sure they are redundant.
1089 if (mSuplServerHost != null) {
1090 native_set_agps_server(AGPS_TYPE_SUPL, mSuplServerHost, mSuplServerPort);
1092 if (mC2KServerHost != null) {
1093 native_set_agps_server(AGPS_TYPE_C2K, mC2KServerHost, mC2KServerPort);
1096 mGnssMeasurementsProvider.onGpsEnabledChanged();
1097 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1099 synchronized (mLock) {
1102 Log.w(TAG, "Failed to enable location provider");
1107 * Disables this provider. When disabled, calls to getStatus()
1108 * need not be handled. Hardware may be shut
1109 * down while the provider is disabled.
1112 public void disable() {
1113 synchronized (mLock) {
1114 if (!mEnabled) return;
1118 sendMessage(ENABLE, 0, null);
1121 private void handleDisable() {
1122 if (DEBUG) Log.d(TAG, "handleDisable");
1124 updateClientUids(new WorkSource());
1126 mAlarmManager.cancel(mWakeupIntent);
1127 mAlarmManager.cancel(mTimeoutIntent);
1129 // do this before releasing wakelock
1132 mGnssMeasurementsProvider.onGpsEnabledChanged();
1133 mGnssNavigationMessageProvider.onGpsEnabledChanged();
1137 public boolean isEnabled() {
1138 synchronized (mLock) {
1144 public int getStatus(Bundle extras) {
1145 if (extras != null) {
1146 extras.putInt("satellites", mSvCount);
1151 private void updateStatus(int status, int svCount) {
1152 if (status != mStatus || svCount != mSvCount) {
1155 mLocationExtras.putInt("satellites", svCount);
1156 mStatusUpdateTime = SystemClock.elapsedRealtime();
1161 public long getStatusUpdateTime() {
1162 return mStatusUpdateTime;
1166 public void setRequest(ProviderRequest request, WorkSource source) {
1167 sendMessage(SET_REQUEST, 0, new GpsRequest(request, source));
1170 private void handleSetRequest(ProviderRequest request, WorkSource source) {
1171 mProviderRequest = request;
1172 mWorkSource = source;
1173 updateRequirements();
1176 // Called when the requirements for GPS may have changed
1177 private void updateRequirements() {
1178 if (mProviderRequest == null || mWorkSource == null) {
1182 boolean singleShot = false;
1184 // see if the request is for a single update
1185 if (mProviderRequest.locationRequests != null
1186 && mProviderRequest.locationRequests.size() > 0) {
1187 // if any request has zero or more than one updates
1188 // requested, then this is not single-shot mode
1191 for (LocationRequest lr : mProviderRequest.locationRequests) {
1192 if (lr.getNumUpdates() != 1) {
1198 if (DEBUG) Log.d(TAG, "setRequest " + mProviderRequest);
1199 if (mProviderRequest.reportLocation && !mDisableGps && isEnabled()) {
1200 // update client uids
1201 updateClientUids(mWorkSource);
1203 mFixInterval = (int) mProviderRequest.interval;
1205 // check for overflow
1206 if (mFixInterval != mProviderRequest.interval) {
1207 Log.w(TAG, "interval overflow: " + mProviderRequest.interval);
1208 mFixInterval = Integer.MAX_VALUE;
1211 // apply request to GPS engine
1212 if (mStarted && hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1214 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1215 mFixInterval, 0, 0)) {
1216 Log.e(TAG, "set_position_mode failed in setMinTime()");
1218 } else if (!mStarted) {
1220 startNavigating(singleShot);
1223 updateClientUids(new WorkSource());
1226 mAlarmManager.cancel(mWakeupIntent);
1227 mAlarmManager.cancel(mTimeoutIntent);
1231 private void updateClientUids(WorkSource source) {
1232 // Update work source.
1233 WorkSource[] changes = mClientSource.setReturningDiffs(source);
1234 if (changes == null) {
1237 WorkSource newWork = changes[0];
1238 WorkSource goneWork = changes[1];
1240 // Update sources that were not previously tracked.
1241 if (newWork != null) {
1243 for (int i=0; i<newWork.size(); i++) {
1245 int uid = newWork.get(i);
1246 mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService),
1247 AppOpsManager.OP_GPS, uid, newWork.getName(i));
1248 if (uid != lastuid) {
1250 mBatteryStats.noteStartGps(uid);
1252 } catch (RemoteException e) {
1253 Log.w(TAG, "RemoteException", e);
1258 // Update sources that are no longer tracked.
1259 if (goneWork != null) {
1261 for (int i=0; i<goneWork.size(); i++) {
1263 int uid = goneWork.get(i);
1264 mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService),
1265 AppOpsManager.OP_GPS, uid, goneWork.getName(i));
1266 if (uid != lastuid) {
1268 mBatteryStats.noteStopGps(uid);
1270 } catch (RemoteException e) {
1271 Log.w(TAG, "RemoteException", e);
1278 public boolean sendExtraCommand(String command, Bundle extras) {
1280 long identity = Binder.clearCallingIdentity();
1281 boolean result = false;
1283 if ("delete_aiding_data".equals(command)) {
1284 result = deleteAidingData(extras);
1285 } else if ("force_time_injection".equals(command)) {
1288 } else if ("force_xtra_injection".equals(command)) {
1289 if (mSupportsXtra) {
1290 xtraDownloadRequest();
1294 Log.w(TAG, "sendExtraCommand: unknown command " + command);
1297 Binder.restoreCallingIdentity(identity);
1301 private IGpsGeofenceHardware mGpsGeofenceBinder = new IGpsGeofenceHardware.Stub() {
1302 public boolean isHardwareGeofenceSupported() {
1303 return native_is_geofence_supported();
1306 public boolean addCircularHardwareGeofence(int geofenceId, double latitude,
1307 double longitude, double radius, int lastTransition, int monitorTransitions,
1308 int notificationResponsiveness, int unknownTimer) {
1309 return native_add_geofence(geofenceId, latitude, longitude, radius,
1310 lastTransition, monitorTransitions, notificationResponsiveness, unknownTimer);
1313 public boolean removeHardwareGeofence(int geofenceId) {
1314 return native_remove_geofence(geofenceId);
1317 public boolean pauseHardwareGeofence(int geofenceId) {
1318 return native_pause_geofence(geofenceId);
1321 public boolean resumeHardwareGeofence(int geofenceId, int monitorTransition) {
1322 return native_resume_geofence(geofenceId, monitorTransition);
1326 private boolean deleteAidingData(Bundle extras) {
1329 if (extras == null) {
1330 flags = GPS_DELETE_ALL;
1333 if (extras.getBoolean("ephemeris")) flags |= GPS_DELETE_EPHEMERIS;
1334 if (extras.getBoolean("almanac")) flags |= GPS_DELETE_ALMANAC;
1335 if (extras.getBoolean("position")) flags |= GPS_DELETE_POSITION;
1336 if (extras.getBoolean("time")) flags |= GPS_DELETE_TIME;
1337 if (extras.getBoolean("iono")) flags |= GPS_DELETE_IONO;
1338 if (extras.getBoolean("utc")) flags |= GPS_DELETE_UTC;
1339 if (extras.getBoolean("health")) flags |= GPS_DELETE_HEALTH;
1340 if (extras.getBoolean("svdir")) flags |= GPS_DELETE_SVDIR;
1341 if (extras.getBoolean("svsteer")) flags |= GPS_DELETE_SVSTEER;
1342 if (extras.getBoolean("sadata")) flags |= GPS_DELETE_SADATA;
1343 if (extras.getBoolean("rti")) flags |= GPS_DELETE_RTI;
1344 if (extras.getBoolean("celldb-info")) flags |= GPS_DELETE_CELLDB_INFO;
1345 if (extras.getBoolean("all")) flags |= GPS_DELETE_ALL;
1349 native_delete_aiding_data(flags);
1356 private void startNavigating(boolean singleShot) {
1358 if (DEBUG) Log.d(TAG, "startNavigating, singleShot is " + singleShot);
1359 mTimeToFirstFix = 0;
1362 mSingleShot = singleShot;
1363 mPositionMode = GPS_POSITION_MODE_STANDALONE;
1365 boolean agpsEnabled =
1366 (Settings.Global.getInt(mContext.getContentResolver(),
1367 Settings.Global.ASSISTED_GPS_ENABLED, 1) != 0);
1368 mPositionMode = getSuplMode(mProperties, agpsEnabled, singleShot);
1373 switch(mPositionMode) {
1374 case GPS_POSITION_MODE_STANDALONE:
1375 mode = "standalone";
1377 case GPS_POSITION_MODE_MS_ASSISTED:
1378 mode = "MS_ASSISTED";
1380 case GPS_POSITION_MODE_MS_BASED:
1387 Log.d(TAG, "setting position_mode to " + mode);
1390 int interval = (hasCapability(GPS_CAPABILITY_SCHEDULING) ? mFixInterval : 1000);
1391 if (!native_set_position_mode(mPositionMode, GPS_POSITION_RECURRENCE_PERIODIC,
1394 Log.e(TAG, "set_position_mode failed in startNavigating()");
1397 if (!native_start()) {
1399 Log.e(TAG, "native_start failed in startNavigating()");
1403 // reset SV count to zero
1404 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1405 mFixRequestTime = System.currentTimeMillis();
1406 if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
1407 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
1408 // and our fix interval is not short
1409 if (mFixInterval >= NO_FIX_TIMEOUT) {
1410 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1411 SystemClock.elapsedRealtime() + NO_FIX_TIMEOUT, mTimeoutIntent);
1417 private void stopNavigating() {
1418 if (DEBUG) Log.d(TAG, "stopNavigating");
1421 mSingleShot = false;
1423 mTimeToFirstFix = 0;
1425 mLocationFlags = LOCATION_INVALID;
1427 // reset SV count to zero
1428 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
1432 private void hibernate() {
1433 // stop GPS until our next fix interval arrives
1435 mAlarmManager.cancel(mTimeoutIntent);
1436 mAlarmManager.cancel(mWakeupIntent);
1437 long now = SystemClock.elapsedRealtime();
1438 mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, now + mFixInterval, mWakeupIntent);
1441 private boolean hasCapability(int capability) {
1442 return ((mEngineCapabilities & capability) != 0);
1447 * called from native code to update our position.
1449 private void reportLocation(int flags, double latitude, double longitude, double altitude,
1450 float speed, float bearing, float accuracy, long timestamp) {
1451 if (VERBOSE) Log.v(TAG, "reportLocation lat: " + latitude + " long: " + longitude +
1452 " timestamp: " + timestamp);
1454 synchronized (mLocation) {
1455 mLocationFlags = flags;
1456 if ((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1457 mLocation.setLatitude(latitude);
1458 mLocation.setLongitude(longitude);
1459 mLocation.setTime(timestamp);
1460 // It would be nice to push the elapsed real-time timestamp
1461 // further down the stack, but this is still useful
1462 mLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1464 if ((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1465 mLocation.setAltitude(altitude);
1467 mLocation.removeAltitude();
1469 if ((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1470 mLocation.setSpeed(speed);
1472 mLocation.removeSpeed();
1474 if ((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1475 mLocation.setBearing(bearing);
1477 mLocation.removeBearing();
1479 if ((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1480 mLocation.setAccuracy(accuracy);
1482 mLocation.removeAccuracy();
1484 mLocation.setExtras(mLocationExtras);
1487 mILocationManager.reportLocation(mLocation, false);
1488 } catch (RemoteException e) {
1489 Log.e(TAG, "RemoteException calling reportLocation");
1493 mLastFixTime = System.currentTimeMillis();
1494 // report time to first fix
1495 if (mTimeToFirstFix == 0 && (flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1496 mTimeToFirstFix = (int)(mLastFixTime - mFixRequestTime);
1497 if (DEBUG) Log.d(TAG, "TTFF: " + mTimeToFirstFix);
1499 // notify status listeners
1500 mListenerHelper.onFirstFix(mTimeToFirstFix);
1507 if (mStarted && mStatus != LocationProvider.AVAILABLE) {
1508 // we want to time out if we do not receive a fix
1509 // within the time out and we are requesting infrequent fixes
1510 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mFixInterval < NO_FIX_TIMEOUT) {
1511 mAlarmManager.cancel(mTimeoutIntent);
1514 // send an intent to notify that the GPS is receiving fixes.
1515 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1516 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
1517 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1518 updateStatus(LocationProvider.AVAILABLE, mSvCount);
1521 if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
1522 mFixInterval > GPS_POLLING_THRESHOLD_INTERVAL) {
1523 if (DEBUG) Log.d(TAG, "got fix, hibernating");
1529 * called from native code to update our status
1531 private void reportStatus(int status) {
1532 if (DEBUG) Log.v(TAG, "reportStatus status: " + status);
1534 boolean wasNavigating = mNavigating;
1536 case GPS_STATUS_SESSION_BEGIN:
1540 case GPS_STATUS_SESSION_END:
1541 mNavigating = false;
1543 case GPS_STATUS_ENGINE_ON:
1546 case GPS_STATUS_ENGINE_OFF:
1548 mNavigating = false;
1552 if (wasNavigating != mNavigating) {
1553 mListenerHelper.onStatusChanged(mNavigating);
1555 // send an intent to notify that the GPS has been enabled or disabled
1556 Intent intent = new Intent(LocationManager.GPS_ENABLED_CHANGE_ACTION);
1557 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, mNavigating);
1558 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1563 * called from native code to update SV info
1565 private void reportSvStatus() {
1566 int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
1567 mListenerHelper.onSvStatusChanged(
1575 Log.v(TAG, "SV count: " + svCount);
1577 // Calculate number of sets used in fix.
1578 int usedInFixCount = 0;
1579 for (int i = 0; i < svCount; i++) {
1580 if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
1584 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
1585 " cn0: " + mCn0s[i]/10 +
1586 " elev: " + mSvElevations[i] +
1587 " azimuth: " + mSvAzimuths[i] +
1588 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
1590 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_ALMANAC_DATA) == 0
1592 ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) == 0
1596 // return number of sets used in fix instead of total
1597 updateStatus(mStatus, usedInFixCount);
1599 if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
1600 System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
1601 // send an intent to notify that the GPS is no longer receiving fixes.
1602 Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
1603 intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
1604 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1605 updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
1610 * called from native code to update AGPS status
1612 private void reportAGpsStatus(int type, int status, byte[] ipaddr) {
1614 case GPS_REQUEST_AGPS_DATA_CONN:
1615 if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
1616 Log.v(TAG, "Received SUPL IP addr[]: " + Arrays.toString(ipaddr));
1617 InetAddress connectionIpAddress = null;
1618 if (ipaddr != null) {
1620 connectionIpAddress = InetAddress.getByAddress(ipaddr);
1621 if (DEBUG) Log.d(TAG, "IP address converted to: " + connectionIpAddress);
1622 } catch (UnknownHostException e) {
1623 Log.e(TAG, "Bad IP Address: " + ipaddr, e);
1626 sendMessage(REQUEST_SUPL_CONNECTION, 0 /*arg*/, connectionIpAddress);
1628 case GPS_RELEASE_AGPS_DATA_CONN:
1629 if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
1630 releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
1632 case GPS_AGPS_DATA_CONNECTED:
1633 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
1635 case GPS_AGPS_DATA_CONN_DONE:
1636 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
1638 case GPS_AGPS_DATA_CONN_FAILED:
1639 if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
1642 if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + status);
1646 private void releaseSuplConnection(int connStatus) {
1647 sendMessage(RELEASE_SUPL_CONNECTION, connStatus, null /*obj*/);
1651 * called from native code to report NMEA data received
1653 private void reportNmea(long timestamp) {
1654 int length = native_read_nmea(mNmeaBuffer, mNmeaBuffer.length);
1655 String nmea = new String(mNmeaBuffer, 0 /* offset */, length);
1656 mListenerHelper.onNmeaReceived(timestamp, nmea);
1660 * called from native code - Gps measurements callback
1662 private void reportMeasurementData(GnssMeasurementsEvent event) {
1663 mGnssMeasurementsProvider.onMeasurementsAvailable(event);
1667 * called from native code - GPS navigation message callback
1669 private void reportNavigationMessage(GnssNavigationMessage event) {
1670 mGnssNavigationMessageProvider.onNavigationMessageAvailable(event);
1674 * called from native code to inform us what the GPS engine capabilities are
1676 private void setEngineCapabilities(int capabilities) {
1677 mEngineCapabilities = capabilities;
1679 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) {
1680 mOnDemandTimeInjection = true;
1684 mGnssMeasurementsProvider.onCapabilitiesUpdated(
1685 (capabilities & GPS_CAPABILITY_MEASUREMENTS) == GPS_CAPABILITY_MEASUREMENTS);
1686 mGnssNavigationMessageProvider.onCapabilitiesUpdated(
1687 (capabilities & GPS_CAPABILITY_NAV_MESSAGES) == GPS_CAPABILITY_NAV_MESSAGES);
1691 * Called from native code to inform us the hardware information.
1693 private void setGnssYearOfHardware(int yearOfHardware) {
1694 if (DEBUG) Log.d(TAG, "setGnssYearOfHardware called with " + yearOfHardware);
1695 mYearOfHardware = yearOfHardware;
1698 public interface GnssSystemInfoProvider {
1700 * Returns the year of GPS hardware.
1702 int getGnssYearOfHardware();
1708 public GnssSystemInfoProvider getGnssSystemInfoProvider() {
1709 return new GnssSystemInfoProvider() {
1711 public int getGnssYearOfHardware() {
1712 return mYearOfHardware;
1718 * called from native code to request XTRA data
1720 private void xtraDownloadRequest() {
1721 if (DEBUG) Log.d(TAG, "xtraDownloadRequest");
1722 sendMessage(DOWNLOAD_XTRA_DATA, 0, null);
1726 * Helper method to construct a location object.
1728 private Location buildLocation(
1737 Location location = new Location(LocationManager.GPS_PROVIDER);
1738 if((flags & LOCATION_HAS_LAT_LONG) == LOCATION_HAS_LAT_LONG) {
1739 location.setLatitude(latitude);
1740 location.setLongitude(longitude);
1741 location.setTime(timestamp);
1742 location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
1744 if((flags & LOCATION_HAS_ALTITUDE) == LOCATION_HAS_ALTITUDE) {
1745 location.setAltitude(altitude);
1747 if((flags & LOCATION_HAS_SPEED) == LOCATION_HAS_SPEED) {
1748 location.setSpeed(speed);
1750 if((flags & LOCATION_HAS_BEARING) == LOCATION_HAS_BEARING) {
1751 location.setBearing(bearing);
1753 if((flags & LOCATION_HAS_ACCURACY) == LOCATION_HAS_ACCURACY) {
1754 location.setAccuracy(accuracy);
1760 * Converts the GPS HAL status to the internal Geofence Hardware status.
1762 private int getGeofenceStatus(int status) {
1764 case GPS_GEOFENCE_OPERATION_SUCCESS:
1765 return GeofenceHardware.GEOFENCE_SUCCESS;
1766 case GPS_GEOFENCE_ERROR_GENERIC:
1767 return GeofenceHardware.GEOFENCE_FAILURE;
1768 case GPS_GEOFENCE_ERROR_ID_EXISTS:
1769 return GeofenceHardware.GEOFENCE_ERROR_ID_EXISTS;
1770 case GPS_GEOFENCE_ERROR_INVALID_TRANSITION:
1771 return GeofenceHardware.GEOFENCE_ERROR_INVALID_TRANSITION;
1772 case GPS_GEOFENCE_ERROR_TOO_MANY_GEOFENCES:
1773 return GeofenceHardware.GEOFENCE_ERROR_TOO_MANY_GEOFENCES;
1774 case GPS_GEOFENCE_ERROR_ID_UNKNOWN:
1775 return GeofenceHardware.GEOFENCE_ERROR_ID_UNKNOWN;
1782 * Called from native to report GPS Geofence transition
1783 * All geofence callbacks are called on the same thread
1785 private void reportGeofenceTransition(int geofenceId, int flags, double latitude,
1786 double longitude, double altitude, float speed, float bearing, float accuracy,
1787 long timestamp, int transition, long transitionTimestamp) {
1788 if (mGeofenceHardwareImpl == null) {
1789 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1791 Location location = buildLocation(
1800 mGeofenceHardwareImpl.reportGeofenceTransition(
1804 transitionTimestamp,
1805 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1806 FusedBatchOptions.SourceTechnologies.GNSS);
1810 * called from native code to report GPS status change.
1812 private void reportGeofenceStatus(int status, int flags, double latitude,
1813 double longitude, double altitude, float speed, float bearing, float accuracy,
1815 if (mGeofenceHardwareImpl == null) {
1816 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1818 Location location = buildLocation(
1827 int monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_UNAVAILABLE;
1828 if(status == GPS_GEOFENCE_AVAILABLE) {
1829 monitorStatus = GeofenceHardware.MONITOR_CURRENTLY_AVAILABLE;
1831 mGeofenceHardwareImpl.reportGeofenceMonitorStatus(
1832 GeofenceHardware.MONITORING_TYPE_GPS_HARDWARE,
1835 FusedBatchOptions.SourceTechnologies.GNSS);
1839 * called from native code - Geofence Add callback
1841 private void reportGeofenceAddStatus(int geofenceId, int status) {
1842 if (mGeofenceHardwareImpl == null) {
1843 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1845 mGeofenceHardwareImpl.reportGeofenceAddStatus(geofenceId, getGeofenceStatus(status));
1849 * called from native code - Geofence Remove callback
1851 private void reportGeofenceRemoveStatus(int geofenceId, int status) {
1852 if (mGeofenceHardwareImpl == null) {
1853 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1855 mGeofenceHardwareImpl.reportGeofenceRemoveStatus(geofenceId, getGeofenceStatus(status));
1859 * called from native code - Geofence Pause callback
1861 private void reportGeofencePauseStatus(int geofenceId, int status) {
1862 if (mGeofenceHardwareImpl == null) {
1863 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1865 mGeofenceHardwareImpl.reportGeofencePauseStatus(geofenceId, getGeofenceStatus(status));
1869 * called from native code - Geofence Resume callback
1871 private void reportGeofenceResumeStatus(int geofenceId, int status) {
1872 if (mGeofenceHardwareImpl == null) {
1873 mGeofenceHardwareImpl = GeofenceHardwareImpl.getInstance(mContext);
1875 mGeofenceHardwareImpl.reportGeofenceResumeStatus(geofenceId, getGeofenceStatus(status));
1878 //=============================================================
1879 // NI Client support
1880 //=============================================================
1881 private final INetInitiatedListener mNetInitiatedListener = new INetInitiatedListener.Stub() {
1882 // Sends a response for an NI request to HAL.
1884 public boolean sendNiResponse(int notificationId, int userResponse)
1886 // TODO Add Permission check
1888 if (DEBUG) Log.d(TAG, "sendNiResponse, notifId: " + notificationId +
1889 ", response: " + userResponse);
1890 native_send_ni_response(notificationId, userResponse);
1895 public INetInitiatedListener getNetInitiatedListener() {
1896 return mNetInitiatedListener;
1899 // Called by JNI function to report an NI request.
1900 public void reportNiNotification(
1905 int defaultResponse,
1908 int requestorIdEncoding,
1910 String extras // Encoded extra data
1913 Log.i(TAG, "reportNiNotification: entered");
1914 Log.i(TAG, "notificationId: " + notificationId +
1915 ", niType: " + niType +
1916 ", notifyFlags: " + notifyFlags +
1917 ", timeout: " + timeout +
1918 ", defaultResponse: " + defaultResponse);
1920 Log.i(TAG, "requestorId: " + requestorId +
1922 ", requestorIdEncoding: " + requestorIdEncoding +
1923 ", textEncoding: " + textEncoding);
1925 GpsNiNotification notification = new GpsNiNotification();
1927 notification.notificationId = notificationId;
1928 notification.niType = niType;
1929 notification.needNotify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_NOTIFY) != 0;
1930 notification.needVerify = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_NEED_VERIFY) != 0;
1931 notification.privacyOverride = (notifyFlags & GpsNetInitiatedHandler.GPS_NI_PRIVACY_OVERRIDE) != 0;
1932 notification.timeout = timeout;
1933 notification.defaultResponse = defaultResponse;
1934 notification.requestorId = requestorId;
1935 notification.text = text;
1936 notification.requestorIdEncoding = requestorIdEncoding;
1937 notification.textEncoding = textEncoding;
1939 // Process extras, assuming the format is
1940 // one of more lines of "key = value"
1941 Bundle bundle = new Bundle();
1943 if (extras == null) extras = "";
1944 Properties extraProp = new Properties();
1947 extraProp.load(new StringReader(extras));
1949 catch (IOException e)
1951 Log.e(TAG, "reportNiNotification cannot parse extras data: " + extras);
1954 for (Entry<Object, Object> ent : extraProp.entrySet())
1956 bundle.putString((String) ent.getKey(), (String) ent.getValue());
1959 notification.extras = bundle;
1961 mNIHandler.handleNiNotification(notification);
1965 * Called from native code to request set id info.
1966 * We should be careful about receiving null string from the TelephonyManager,
1967 * because sending null String to JNI function would cause a crash.
1970 private void requestSetID(int flags) {
1971 TelephonyManager phone = (TelephonyManager)
1972 mContext.getSystemService(Context.TELEPHONY_SERVICE);
1973 int type = AGPS_SETID_TYPE_NONE;
1976 if ((flags & AGPS_RIL_REQUEST_SETID_IMSI) == AGPS_RIL_REQUEST_SETID_IMSI) {
1977 String data_temp = phone.getSubscriberId();
1978 if (data_temp == null) {
1979 // This means the framework does not have the SIM card ready.
1981 // This means the framework has the SIM card.
1983 type = AGPS_SETID_TYPE_IMSI;
1986 else if ((flags & AGPS_RIL_REQUEST_SETID_MSISDN) == AGPS_RIL_REQUEST_SETID_MSISDN) {
1987 String data_temp = phone.getLine1Number();
1988 if (data_temp == null) {
1989 // This means the framework does not have the SIM card ready.
1991 // This means the framework has the SIM card.
1993 type = AGPS_SETID_TYPE_MSISDN;
1996 native_agps_set_id(type, data);
2000 * Called from native code to request utc time info
2002 private void requestUtcTime() {
2003 if (DEBUG) Log.d(TAG, "utcTimeRequest");
2004 sendMessage(INJECT_NTP_TIME, 0, null);
2008 * Called from native code to request reference location info
2011 private void requestRefLocation(int flags) {
2012 TelephonyManager phone = (TelephonyManager)
2013 mContext.getSystemService(Context.TELEPHONY_SERVICE);
2014 final int phoneType = phone.getPhoneType();
2015 if (phoneType == TelephonyManager.PHONE_TYPE_GSM) {
2016 GsmCellLocation gsm_cell = (GsmCellLocation) phone.getCellLocation();
2017 if ((gsm_cell != null) && (phone.getNetworkOperator() != null)
2018 && (phone.getNetworkOperator().length() > 3)) {
2020 int mcc = Integer.parseInt(phone.getNetworkOperator().substring(0,3));
2021 int mnc = Integer.parseInt(phone.getNetworkOperator().substring(3));
2022 int networkType = phone.getNetworkType();
2023 if (networkType == TelephonyManager.NETWORK_TYPE_UMTS
2024 || networkType == TelephonyManager.NETWORK_TYPE_HSDPA
2025 || networkType == TelephonyManager.NETWORK_TYPE_HSUPA
2026 || networkType == TelephonyManager.NETWORK_TYPE_HSPA
2027 || networkType == TelephonyManager.NETWORK_TYPE_HSPAP) {
2028 type = AGPS_REF_LOCATION_TYPE_UMTS_CELLID;
2030 type = AGPS_REF_LOCATION_TYPE_GSM_CELLID;
2032 native_agps_set_ref_location_cellid(type, mcc, mnc,
2033 gsm_cell.getLac(), gsm_cell.getCid());
2035 Log.e(TAG,"Error getting cell location info.");
2037 } else if (phoneType == TelephonyManager.PHONE_TYPE_CDMA) {
2038 Log.e(TAG, "CDMA not supported.");
2042 private void sendMessage(int message, int arg, Object obj) {
2043 // hold a wake lock until this message is delivered
2044 // note that this assumes the message will not be removed from the queue before
2045 // it is handled (otherwise the wake lock would be leaked).
2046 mWakeLock.acquire();
2047 Log.i(TAG, "WakeLock acquired by sendMessage(" + message + ", " + arg + ", " + obj + ")");
2048 mHandler.obtainMessage(message, arg, 1, obj).sendToTarget();
2051 private final class ProviderHandler extends Handler {
2052 public ProviderHandler(Looper looper) {
2053 super(looper, null, true /*async*/);
2057 public void handleMessage(Message msg) {
2058 int message = msg.what;
2061 if (msg.arg1 == 1) {
2068 GpsRequest gpsRequest = (GpsRequest) msg.obj;
2069 handleSetRequest(gpsRequest.request, gpsRequest.source);
2071 case UPDATE_NETWORK_STATE:
2072 handleUpdateNetworkState((Network) msg.obj);
2074 case REQUEST_SUPL_CONNECTION:
2075 handleRequestSuplConnection((InetAddress) msg.obj);
2077 case RELEASE_SUPL_CONNECTION:
2078 handleReleaseSuplConnection(msg.arg1);
2080 case INJECT_NTP_TIME:
2081 handleInjectNtpTime();
2083 case DOWNLOAD_XTRA_DATA:
2084 if (mSupportsXtra) {
2085 handleDownloadXtraData();
2088 case INJECT_NTP_TIME_FINISHED:
2089 mInjectNtpTimePending = STATE_IDLE;
2091 case DOWNLOAD_XTRA_DATA_FINISHED:
2092 mDownloadXtraDataPending = STATE_IDLE;
2094 case UPDATE_LOCATION:
2095 handleUpdateLocation((Location) msg.obj);
2097 case SUBSCRIPTION_OR_SIM_CHANGED:
2098 subscriptionOrSimChanged(mContext);
2100 case INITIALIZE_HANDLER:
2104 if (msg.arg2 == 1) {
2105 // wakelock was taken for this message, release it
2106 mWakeLock.release();
2107 Log.i(TAG, "WakeLock released by handleMessage(" + message + ", " + msg.arg1 + ", "
2113 * This method is bound to {@link #GnssLocationProvider(Context, ILocationManager, Looper)}.
2114 * It is in charge of loading properties and registering for events that will be posted to
2117 private void handleInitialize() {
2118 // load default GPS configuration
2119 // (this configuration might change in the future based on SIM changes)
2120 reloadGpsProperties(mContext, mProperties);
2122 // TODO: When this object "finishes" we should unregister by invoking
2123 // SubscriptionManager.getInstance(mContext).unregister(mOnSubscriptionsChangedListener);
2124 // This is not strictly necessary because it will be unregistered if the
2125 // notification fails but it is good form.
2127 // Register for SubscriptionInfo list changes which is guaranteed
2128 // to invoke onSubscriptionsChanged the first time.
2129 SubscriptionManager.from(mContext)
2130 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
2132 // listen for events
2133 IntentFilter intentFilter;
2134 if (native_is_agps_ril_supported()) {
2135 intentFilter = new IntentFilter();
2136 intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
2137 intentFilter.addDataScheme("sms");
2138 intentFilter.addDataAuthority("localhost", "7275");
2139 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2141 intentFilter = new IntentFilter();
2142 intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
2144 intentFilter.addDataType("application/vnd.omaloc-supl-init");
2145 } catch (IntentFilter.MalformedMimeTypeException e) {
2146 Log.w(TAG, "Malformed SUPL init mime type");
2148 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2150 Log.d(TAG, "Skipped registration for SMS/WAP-PUSH messages because AGPS Ril in GPS"
2151 + " HAL is not supported");
2154 intentFilter = new IntentFilter();
2155 intentFilter.addAction(ALARM_WAKEUP);
2156 intentFilter.addAction(ALARM_TIMEOUT);
2157 intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
2158 intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
2159 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
2160 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
2161 intentFilter.addAction(SIM_STATE_CHANGED);
2162 mContext.registerReceiver(mBroadcastReceiver, intentFilter, null, this);
2164 // register for connectivity change events, this is equivalent to the deprecated way of
2165 // registering for CONNECTIVITY_ACTION broadcasts
2166 NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder();
2167 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
2168 networkRequestBuilder.addTransportType(NetworkCapabilities.TRANSPORT_WIFI);
2169 NetworkRequest networkRequest = networkRequestBuilder.build();
2170 mConnMgr.registerNetworkCallback(networkRequest, mNetworkConnectivityCallback);
2172 // listen for PASSIVE_PROVIDER updates
2173 LocationManager locManager =
2174 (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
2176 float minDistance = 0;
2177 boolean oneShot = false;
2178 LocationRequest request = LocationRequest.createFromDeprecatedProvider(
2179 LocationManager.PASSIVE_PROVIDER,
2183 // Don't keep track of this request since it's done on behalf of other clients
2184 // (which are kept track of separately).
2185 request.setHideFromAppOps(true);
2186 locManager.requestLocationUpdates(
2188 new NetworkLocationListener(),
2193 private final class NetworkLocationListener implements LocationListener {
2195 public void onLocationChanged(Location location) {
2196 // this callback happens on mHandler looper
2197 if (LocationManager.NETWORK_PROVIDER.equals(location.getProvider())) {
2198 handleUpdateLocation(location);
2202 public void onStatusChanged(String provider, int status, Bundle extras) { }
2204 public void onProviderEnabled(String provider) { }
2206 public void onProviderDisabled(String provider) { }
2209 private String getSelectedApn() {
2210 Uri uri = Uri.parse("content://telephony/carriers/preferapn");
2211 Cursor cursor = null;
2213 cursor = mContext.getContentResolver().query(
2215 new String[] { "apn" },
2216 null /* selection */,
2217 null /* selectionArgs */,
2218 Carriers.DEFAULT_SORT_ORDER);
2219 if (cursor != null && cursor.moveToFirst()) {
2220 return cursor.getString(0);
2222 Log.e(TAG, "No APN found to select.");
2224 } catch (Exception e) {
2225 Log.e(TAG, "Error encountered on selecting the APN.", e);
2227 if (cursor != null) {
2235 private int getApnIpType(String apn) {
2236 ensureInHandlerThread();
2241 String selection = String.format("current = 1 and apn = '%s' and carrier_enabled = 1", apn);
2242 Cursor cursor = null;
2244 cursor = mContext.getContentResolver().query(
2245 Carriers.CONTENT_URI,
2246 new String[] { Carriers.PROTOCOL },
2249 Carriers.DEFAULT_SORT_ORDER);
2251 if (null != cursor && cursor.moveToFirst()) {
2252 return translateToApnIpType(cursor.getString(0), apn);
2254 Log.e(TAG, "No entry found in query for APN: " + apn);
2256 } catch (Exception e) {
2257 Log.e(TAG, "Error encountered on APN query for: " + apn, e);
2259 if (cursor != null) {
2267 private int translateToApnIpType(String ipProtocol, String apn) {
2268 if ("IP".equals(ipProtocol)) {
2271 if ("IPV6".equals(ipProtocol)) {
2274 if ("IPV4V6".equals(ipProtocol)) {
2278 // we hit the default case so the ipProtocol is not recognized
2279 String message = String.format("Unknown IP Protocol: %s, for APN: %s", ipProtocol, apn);
2280 Log.e(TAG, message);
2284 private void setRouting() {
2285 if (mAGpsDataConnectionIpAddr == null) {
2289 // TODO: replace the use of this deprecated API
2290 boolean result = mConnMgr.requestRouteToHostAddress(
2291 ConnectivityManager.TYPE_MOBILE_SUPL,
2292 mAGpsDataConnectionIpAddr);
2295 Log.e(TAG, "Error requesting route to host: " + mAGpsDataConnectionIpAddr);
2297 Log.d(TAG, "Successfully requested route to host: " + mAGpsDataConnectionIpAddr);
2302 * @return {@code true} if there is a data network available for outgoing connections,
2303 * {@code false} otherwise.
2305 private boolean isDataNetworkConnected() {
2306 NetworkInfo activeNetworkInfo = mConnMgr.getActiveNetworkInfo();
2307 return activeNetworkInfo != null && activeNetworkInfo.isConnected();
2311 * Ensures the calling function is running in the thread associated with {@link #mHandler}.
2313 private void ensureInHandlerThread() {
2314 if (mHandler != null && Looper.myLooper() == mHandler.getLooper()) {
2317 throw new RuntimeException("This method must run on the Handler thread.");
2321 * @return A string representing the current state stored in {@link #mAGpsDataConnectionState}.
2323 private String agpsDataConnStateAsString() {
2324 switch(mAGpsDataConnectionState) {
2325 case AGPS_DATA_CONNECTION_CLOSED:
2327 case AGPS_DATA_CONNECTION_OPEN:
2329 case AGPS_DATA_CONNECTION_OPENING:
2337 * @return A string representing the given GPS_AGPS_DATA status.
2339 private String agpsDataConnStatusAsString(int agpsDataConnStatus) {
2340 switch (agpsDataConnStatus) {
2341 case GPS_AGPS_DATA_CONNECTED:
2343 case GPS_AGPS_DATA_CONN_DONE:
2345 case GPS_AGPS_DATA_CONN_FAILED:
2347 case GPS_RELEASE_AGPS_DATA_CONN:
2349 case GPS_REQUEST_AGPS_DATA_CONN:
2357 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2358 StringBuilder s = new StringBuilder();
2359 s.append(" mFixInterval=").append(mFixInterval).append('\n');
2360 s.append(" mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
2361 s.append(" mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
2363 if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
2364 if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
2365 if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
2366 if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
2367 if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
2368 if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
2369 if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
2370 if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
2373 s.append(native_get_internal_state());
2378 * A simple implementation of exponential backoff.
2380 private static final class BackOff {
2381 private static final int MULTIPLIER = 2;
2382 private final long mInitIntervalMillis;
2383 private final long mMaxIntervalMillis;
2384 private long mCurrentIntervalMillis;
2386 public BackOff(long initIntervalMillis, long maxIntervalMillis) {
2387 mInitIntervalMillis = initIntervalMillis;
2388 mMaxIntervalMillis = maxIntervalMillis;
2390 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2393 public long nextBackoffMillis() {
2394 if (mCurrentIntervalMillis > mMaxIntervalMillis) {
2395 return mMaxIntervalMillis;
2398 mCurrentIntervalMillis *= MULTIPLIER;
2399 return mCurrentIntervalMillis;
2402 public void reset() {
2403 mCurrentIntervalMillis = mInitIntervalMillis / MULTIPLIER;
2407 // for GPS SV statistics
2408 private static final int MAX_SVS = 64;
2410 // preallocated arrays, to avoid memory allocation in reportStatus()
2411 private int mSvidWithFlags[] = new int[MAX_SVS];
2412 private float mCn0s[] = new float[MAX_SVS];
2413 private float mSvElevations[] = new float[MAX_SVS];
2414 private float mSvAzimuths[] = new float[MAX_SVS];
2415 private int mSvCount;
2416 // preallocated to avoid memory allocation in reportNmea()
2417 private byte[] mNmeaBuffer = new byte[120];
2419 static { class_init_native(); }
2420 private static native void class_init_native();
2421 private static native boolean native_is_supported();
2422 private static native boolean native_is_agps_ril_supported();
2423 private static native boolean native_is_gnss_configuration_supported();
2425 private native boolean native_init();
2426 private native void native_cleanup();
2427 private native boolean native_set_position_mode(int mode, int recurrence, int min_interval,
2428 int preferred_accuracy, int preferred_time);
2429 private native boolean native_start();
2430 private native boolean native_stop();
2431 private native void native_delete_aiding_data(int flags);
2432 // returns number of SVs
2433 // mask[0] is ephemeris mask and mask[1] is almanac mask
2434 private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
2436 private native int native_read_nmea(byte[] buffer, int bufferSize);
2437 private native void native_inject_location(double latitude, double longitude, float accuracy);
2440 private native void native_inject_time(long time, long timeReference, int uncertainty);
2441 private native boolean native_supports_xtra();
2442 private native void native_inject_xtra_data(byte[] data, int length);
2445 private native String native_get_internal_state();
2448 private native void native_agps_data_conn_open(String apn, int apnIpType);
2449 private native void native_agps_data_conn_closed();
2450 private native void native_agps_data_conn_failed();
2451 private native void native_agps_ni_message(byte [] msg, int length);
2452 private native void native_set_agps_server(int type, String hostname, int port);
2454 // Network-initiated (NI) Support
2455 private native void native_send_ni_response(int notificationId, int userResponse);
2458 private native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
2460 private native void native_agps_set_id(int type, String setid);
2462 private native void native_update_network_state(boolean connected, int type,
2463 boolean roaming, boolean available, String extraInfo, String defaultAPN);
2465 // Hardware Geofence support.
2466 private static native boolean native_is_geofence_supported();
2467 private static native boolean native_add_geofence(int geofenceId, double latitude,
2468 double longitude, double radius, int lastTransition,int monitorTransitions,
2469 int notificationResponsivenes, int unknownTimer);
2470 private static native boolean native_remove_geofence(int geofenceId);
2471 private static native boolean native_resume_geofence(int geofenceId, int transitions);
2472 private static native boolean native_pause_geofence(int geofenceId);
2474 // Gps Hal measurements support.
2475 private static native boolean native_is_measurement_supported();
2476 private native boolean native_start_measurement_collection();
2477 private native boolean native_stop_measurement_collection();
2479 // Gps Navigation message support.
2480 private static native boolean native_is_navigation_message_supported();
2481 private native boolean native_start_navigation_message_collection();
2482 private native boolean native_stop_navigation_message_collection();
2484 // GNSS Configuration
2485 private static native void native_configuration_update(String configData);